4 Replies Latest reply on Jun 12, 2016 3:27 AM by jshimpf

    How to use qm_uart_irq_read() ?

    jshimpf

      Hi,

           I want to use qm_uart_irq_read() as an interrupt driven serial I/O driver so I can be executing non-interrupt code while receiving serial data.  This requires copying the data from the xfer structure serial buffer to a circular buffer that is accessed by both the code in the UART RX callback and reading it out in the non-interrupt code.  Normally when I do this I need a semaphore or mutex to lock the circular buffer while the non-interrupt side accesses it. 

       

      Is there such an instruction in the D2000 or is there some other way of doing this ?

       

      I have a structure like this to support this operation:

       

      #define RX_SIZE 32

      #define FIFO_SIZE 64

      typedef struct {

             int uart;

             qm_uart_transfer_t xfer;

             int psn;

             int count;

             uint8_t rx_buffer[RX_SIZE];

             int head;

             int tail;

             int size;

             uint8_t fifo[FIFO_SIZE];

        } PORT_HANDLE;

       

      PORT_HANDLE phy;

       

      And it is set up like this:

       

        /* Setup a non-blocking IRQ RX transfer. */

        phy.xfer.data = phy.rx_buffer;

        phy.xfer.data_len = RX_SIZE;

        phy.xfer.fin_callback = uart_0_rx_callback;

        phy.xfer.err_callback = uart_0_error_callback;

        qm_irq_request(QM_IRQ_UART_0, qm_uart_0_isr);

       

        phy.uart = QM_UART_0;

        // Init FIFO

        phy.head = 0;

        phy.tail = 0;

        phy.size = 0;

       

      In the IRQ RX routine I do this:

       

      void uart_0_rx_callback(uint32_t id, uint32_t len)

      {

        int i;

       

        switch (id)

        {

       

             case 1:

             // Trans from rx_buffer to FIFO overwrite head

             if( len > 0 )

             {

                  for( i=0; i<(int)len; i++ )

                  {

                       phy.fifo[phy.head++] = phy.rx_buffer[i];

                       if( phy.head >= FIFO_SIZE )

                       phy.head = 0;

                  }

             }

             break;

             default:

             break;

        }

      }

       

      Thanks for the help

       

      --jim schimpf

        • 1. Re: How to use qm_uart_irq_read() ?
          jshimpf

          Slight error in the code (above):

          the setup:

          phy.xfer.fin_callback = uart_0_rx_callback;

            phy.xfer.err_callback = uart_0_error_callback;

            qm_irq_request(QM_IRQ_UART_0, qm_uart_0_isr);

           

          should be

          phy.xfer.fin_callback = uart_0_rx_callback;

            phy.xfer.err_callback = uart_0_error_callback;

            qm_uart_irq_read(QM_UART_0, &(phy.xfer));    <-- Fixed this line.

           

          HOW TO USE IT:

          Found out how to use qm_uart_irq_read().  (1) Set up the xfer structure so it can get data.  (2) Set up an irq routine to catch the data.  (3) Call qm_uart_irq_read() with the UART # and the xfer struct in the setup.  Now it will call the IRQ routine when the buffer is FULL, not before so make the buffer small so it calls the irq say on every char.  (4) In the IRQ routine call qm_uart_irq_read() after emptying the buffer so it runs AGAIN.

          • 2. Re: How to use qm_uart_irq_read() ?
            Intel_Alvarado

            Hi

             

            Have you managed to solve your issue and use qm_uart_irq_read()? Is there anything else we can assist you with in this thread? Remember if you found the solution to your question you can mark the answer as “Correct Answer”

             

            Sergio

            • 3. Re: How to use qm_uart_irq_read() ?
              jshimpf

              Not quite. 

                   Working with the UART sample project I modified it to (1) have a loop at the end so it never exits main (i.e. runs forever) (2) modified the BIG_NUMBER from 50 to 1 so I get an interrupt/character.  But when I transferred this code to my application it would not generate an interrupt on serial in.  I then when back to the UART project and found if I didn't do the TX interrupt setup and output, no RX interrupts would be generated.  So I put that back in and RX interrupts worked.  Why would this be the case particularly since the xfer structure is used for the TX then re-used for the RX ? Here is the UART main.c that generates an interrupt call on each serial character. I marked the modifications.

               

               

              #include "qm_pinmux.h"

              #include "qm_uart.h"

              #include "qm_interrupt.h"

              #include "qm_scss.h"

               

              #define BANNER_STR ("Hello, world!  QMSI echo application, Pol'd message.\n\n")

               

              #define BANNER_IRQ_ID (1)

              #define BANNER_IRQ ("Hello, world!  QMSI echo application, IRQ'd message.\n\n")

              #define BANNER_IRQ_COMPLETE ("IRQ Transfer completed.\n")

               

              #define RX_STR ("Data received.\n")

              #define ERR_STR ("Transmission error.\n")

               

              #define CLR_SCREEN ("\033[2J\033[;H")

               

              static void uart_0_example_tx_callback(uint32_t id, uint32_t len);

              static void uart_0_example_rx_callback(uint32_t id, uint32_t len);

              static void uart_0_example_error_callback(uint32_t id, qm_uart_status_t status);

               

              #define BIG_NUMBER_RX (1)   /*  <<<<<<<<<<<<<<<<<<<<< Set for 1 character interrupt */

              static uint8_t rx_buffer[BIG_NUMBER_RX];

              qm_uart_transfer_t xfer;

               

              /* Sample UART0 QMSI application. */

              int main(void)

              {

                qm_uart_config_t cfg, rd_cfg;

               

                qm_uart_status_t ret __attribute__((unused));

               

                /* Set divisors to yield 115200bps baud rate. */

                /* Sysclk is set by boot ROM to hybrid osc in crystal mode (32MHz),

                * peripheral clock divisor set to 1.

                */

                cfg.baud_divisor = QM_UART_CFG_BAUD_DL_PACK(0, 17, 6);

               

                cfg.line_control = QM_UART_LC_8N1;

                cfg.hw_fc = false;

               

              /* Mux out UART0 tx/rx pins and enable input for rx. */

              #if (QUARK_SE)

                qm_pmux_select(QM_PIN_ID_18, QM_PMUX_FN_0);

                qm_pmux_select(QM_PIN_ID_19, QM_PMUX_FN_0);

                qm_pmux_input_en(QM_PIN_ID_18, true);

               

              #elif(QUARK_D2000)

                qm_pmux_select(QM_PIN_ID_12, QM_PMUX_FN_2);

                qm_pmux_select(QM_PIN_ID_13, QM_PMUX_FN_2);

                qm_pmux_input_en(QM_PIN_ID_13, true);

               

              #else

              #error("Unsupported / unspecified processor detected.")

              #endif

               

                clk_periph_enable(CLK_PERIPH_CLK | CLK_PERIPH_UARTA_REGISTER);

                qm_uart_set_config(QM_UART_0, &cfg);

                qm_uart_get_config(QM_UART_0, &rd_cfg);

               

                qm_uart_write_buffer(QM_UART_0, (uint8_t *)CLR_SCREEN,

                    sizeof(CLR_SCREEN));

                qm_uart_write_buffer(QM_UART_0, (uint8_t *)BANNER_STR,

                    sizeof(BANNER_STR));

               

                /* Setup xfer for IRQ transfer. */   /*   <<<<<<<<<<<<<<<<< Why do I have to do this ????? <<<<<<<<< */

               

                xfer.data = (uint8_t *)BANNER_IRQ;

                xfer.data_len = sizeof(BANNER_IRQ);

                xfer.fin_callback = uart_0_example_tx_callback;

                xfer.err_callback = uart_0_example_error_callback;

                xfer.id = BANNER_IRQ_ID;

               

                qm_irq_request(QM_IRQ_UART_0, qm_uart_0_isr);

               

                /* Transmit IRQ hello world string. */

               

                ret = qm_uart_irq_write(QM_UART_0, &xfer);

                QM_ASSERT(QM_UART_OK == ret);

              /* ******************************************* <<<<<<<<<<<<<< */

               

                /* Setup a non-blocking IRQ RX transfer. */

                xfer.data = rx_buffer;

                xfer.data_len = BIG_NUMBER_RX;

                xfer.fin_callback = uart_0_example_rx_callback;

                xfer.err_callback = uart_0_example_error_callback;

                ret = qm_uart_irq_read(QM_UART_0, &xfer);

                QM_ASSERT(QM_UART_OK == ret);

               

                /* *********** <<<<<<<<<<<<< */

                /* RUN FOREVER */

                while(1)

                ;

              /* *********** <<<<<<<<<<<<<< */

               

                return 0;

              }

               

              void uart_0_example_tx_callback(uint32_t id, uint32_t len)

              {

                switch (id) {

               

                case BANNER_IRQ_ID:

                qm_uart_write_buffer(QM_UART_0, (uint8_t *)BANNER_IRQ_COMPLETE,

                    sizeof(BANNER_IRQ_COMPLETE));

                break;

               

                default:

                break;

                }

              }

               

               

              void uart_0_example_rx_callback(uint32_t id, uint32_t len)

              {

                qm_uart_status_t ret __attribute__((unused));

               

              / BP here will be hit for each input character   <<<<<<<<<<<<<< */

                switch (id) {

               

                case BANNER_IRQ_ID:

                qm_uart_write_buffer(QM_UART_0, (uint8_t *)RX_STR,

                    sizeof(RX_STR));

                qm_uart_write_buffer(QM_UART_0, rx_buffer, BIG_NUMBER_RX);

                ret = qm_uart_irq_read(QM_UART_0, &xfer);     /*  Have to do this to re-arm for next int <<<<<<<<<<< */

                QM_ASSERT(QM_UART_OK == ret);

               

                break;

                default:

                break;

                }

              }

               

              void uart_0_example_error_callback(uint32_t id, qm_uart_status_t status)

              {

                qm_uart_write_buffer(QM_UART_0, (uint8_t *)ERR_STR, sizeof(ERR_STR));

              }

              • 4. Re: How to use qm_uart_irq_read() ?
                jshimpf

                This code works: You call init_phy to set it up then put_phy() to write data, stat_phy() to check for data and get_phy() to get data. Runs at 115200 as I didn't want to try to figure out QM_UART_CFG_BAUD_DL_PACK(0, 17, 6); at this point.

                 

                --jim schimpf

                 

                #include "qm_pinmux.h"

                #include "qm_uart.h"

                #include "qm_interrupt.h"

                #include "qm_scss.h"

                #include "phy.h"

                 

                #if 0

                  #pragma mark -

                  #pragma mark -- Data --

                #endif

                 

                static void uart_0_error_callback(uint32_t id, qm_uart_status_t status);

                static void uart_0_rx_callback(uint32_t id, uint32_t len);

                static void uart_0_tx_callback(uint32_t id, uint32_t len);

                #define RX_SIZE 1  // Small so lots of int/char

                 

                #define FIFO_SIZE 64

                #define FIRENET_DWELL 100

                 

                typedef struct {

                  int uart;

                  qm_uart_transfer_t xfer; // Int rec struct

                  uint8_t rx_buffer[RX_SIZE]; // Int rec buffer 1 byte

                 

                  // FIFO for foreground operations

                  int head;

                  int tail;

                  uint8_t fifo[FIFO_SIZE];

                  } PORT_HANDLE;

                 

                 

                PORT_HANDLE phy;

                 

                #ifndef false

                  #define false 0

                  #define true 1

                  #define EOF -1

                #endif

                 

                // FOR TX interrupt

                #define BANNER_IRQ_ID (1)

                #define BANNER_IRQ ("\r\n----\r\n")

                #define BANNER_IRQ_COMPLETE ("\r\n****\r\n")

                 

                #if 0

                  #pragma mark -

                  #pragma mark -- External API --

                #endif

                 

                //*************************************************************************

                /*

                *  void *init_phy( char *port ) - Initialize Phy layer

                *

                * INPUT: port - Serial port used (number in list)

                * baud - Baud rate used (ignored) - 115200 used

                *

                * OUTPUT: Return port handle if opened, -1 if problem

                *

                * This is called by each node to get the port used for I/O

                */

                //************************************************************************

                 

                void *init_phy( char *port,int baud )

                {

                  void  *rtnval = 0;

                  qm_uart_config_t cfg, rd_cfg;

                  qm_uart_status_t ret __attribute__((unused));

                 

                  /* Set divisors to yield 115200bps baud rate. */

                  /* Sysclk is set by boot ROM to hybrid osc in crystal mode (32MHz),

                  * peripheral clock divisor set to 1.

                  */

                  cfg.baud_divisor = QM_UART_CFG_BAUD_DL_PACK(0, 17, 6);

                 

                  cfg.line_control = QM_UART_LC_8N1;

                  cfg.hw_fc = false;

                 

                /* Mux out UART0 tx/rx pins and enable input for rx. */

                #if (QUARK_SE)

                  qm_pmux_select(QM_PIN_ID_18, QM_PMUX_FN_0);

                  qm_pmux_select(QM_PIN_ID_19, QM_PMUX_FN_0);

                  qm_pmux_input_en(QM_PIN_ID_18, true);

                 

                #elif(QUARK_D2000)

                  qm_pmux_select(QM_PIN_ID_12, QM_PMUX_FN_2);

                  qm_pmux_select(QM_PIN_ID_13, QM_PMUX_FN_2);

                  qm_pmux_input_en(QM_PIN_ID_13, true);

                 

                #else

                  #error("Unsupported / unspecified processor detected.")

                #endif

                  clk_periph_enable(CLK_PERIPH_CLK | CLK_PERIPH_UARTA_REGISTER);

                  qm_uart_set_config(QM_UART_0, &cfg);

                  qm_uart_get_config(QM_UART_0, &rd_cfg);

                 

                  /***************** TX IRQ *********************/

                  /* Setup xfer for IRQ transfer.  RX doesn't work

                  * unless this is done*/

                 

                  phy.xfer.data = (uint8_t *)BANNER_IRQ;

                  phy.xfer.data_len = sizeof(BANNER_IRQ);

                  phy.xfer.fin_callback = uart_0_tx_callback;

                  phy.xfer.err_callback = uart_0_error_callback;

                  phy.xfer.id = BANNER_IRQ_ID;

                 

                  qm_irq_request(QM_IRQ_UART_0, qm_uart_0_isr);

                 

                  ret = qm_uart_irq_write(QM_UART_0, &(phy.xfer));

                  QM_ASSERT(QM_UART_OK == ret);

                  /*********************************************/

                 

                  /* Setup a non-blocking IRQ RX transfer. */

                  phy.xfer.data = phy.rx_buffer;

                  phy.xfer.data_len = RX_SIZE; // Size of 1

                  phy.xfer.fin_callback = uart_0_rx_callback;

                  phy.xfer.err_callback = uart_0_error_callback;

                  ret = qm_uart_irq_read(QM_UART_0, &(phy.xfer)); // Start read

                  QM_ASSERT(QM_UART_OK == ret);

                 

                  phy.uart = QM_UART_0;

                 

                  // Init FIFO

                 

                  phy.head = 0;

                  phy.tail = 0;

                 

                  rtnval = (void *)&phy;

                 

                  return rtnval;

                }

                 

                //*************************************************************************

                /*

                *  void real_close_phy( int h ) - Close Phy layer

                *

                * INPUT: h - Port handle

                *

                * OUTPUT: NONE

                */

                //************************************************************************

                 

                void close_phy(void  *h )

                {

                }

                 

                //*************************************************************************

                /*

                * int put_phy( unsigned char data, int h ) - Put data into output buffer

                *

                * INPUT: data - Character for output

                * h - PHY handle

                *

                * OUTPUT: 0 - Success, <> 0 failure to store

                *

                */

                //************************************************************************

                 

                int put_phy( unsigned char data,void *h )

                {

                  int rtnval = -1;

                  PORT_HANDLE *hdl = (PORT_HANDLE *)h;

                 

                  rtnval = qm_uart_write(hdl->uart,(unsigned char)data);

                 

                  return( rtnval );

                }

                 

                //*************************************************************************

                /*

                * int stat_phy( int h ) - Is there data to read ?

                *

                * INPUT: h - Phy handle

                *

                * OUTPUT: 1 - We have data, 0 no data

                *

                */

                //************************************************************************

                 

                int stat_phy( void *h )

                {

                  PORT_HANDLE *ph = (PORT_HANDLE *)h;

                 

                  if( ph->head != ph->tail )

                  return true;

                  else

                  return false;

                }

                 

                //*************************************************************************

                /*

                * int real_get_phy( void *h ) - Read data byte

                *

                * INPUT: h - Port handle

                *

                * OUTPUT: Returned data, EOF if no data

                */

                //************************************************************************

                 

                int get_phy( void *h )

                {

                  int rtnval = EOF;

                  int next;

                  PORT_HANDLE *ph = (PORT_HANDLE *)h;

                 

                  // Do we have data, return byte

                 

                  if( ph->tail != ph->head )

                  {

                  next = ph->tail + 1;

                  rtnval = ph->fifo[next];

                  if(next >= FIFO_SIZE )

                  next = 0;

                  ph->tail = next;

                  }

                 

                  return( rtnval );

                }

                 

                #if 0

                  #pragma mark -

                  #pragma mark -- IRQ API --

                #endif

                 

                //*************************************************************************

                /*

                * void uart_0_rx_callback(uint32_t id, uint32_t len) Call back on rx int

                *

                * INPUT: id - UART #

                * len - of data in RX buffer (SB 1)

                *

                * OUTPUT: NONE

                */

                //************************************************************************

                 

                void uart_0_rx_callback(uint32_t id, uint32_t len)

                {

                  int next;

                  qm_uart_status_t ret __attribute__((unused));

                 

                  switch (id)

                  {

                 

                  case 1:

                  // Trans from rx_buffer to FIFO overwrite head

                  if( len > 0 )

                  {

                  next = phy.head + 1;

                  if( next >= FIFO_SIZE )

                  next = 0;

                 

                  // Will it fit ?, if not drop it

                  if( next != phy.tail )

                  {

                  phy.fifo[next] = phy.rx_buffer[0];

                  phy.head = next;

                  }

                  }

                  ret = qm_uart_irq_read(QM_UART_0, &(phy.xfer)); // Restart XFER

                  QM_ASSERT(QM_UART_OK == ret);

                  break;

                 

                  default: // Ignore others

                  break;

                  }

                }

                 

                //*************************************************************************

                /*

                * void uart_0_tx_callback(uint32_t id, uint32_t len) Call back on tx int

                *

                * INPUT: id - Interrupt ID

                * len - of data

                *

                * OUTPUT: NONE

                */

                //************************************************************************

                 

                void uart_0_tx_callback(uint32_t id, uint32_t len)

                {

                  switch (id) {

                 

                  case BANNER_IRQ_ID:

                  qm_uart_write_buffer(QM_UART_0, (uint8_t *)BANNER_IRQ_COMPLETE,

                      sizeof(BANNER_IRQ_COMPLETE));

                  break;

                 

                  default:

                  break;

                  }

                }

                 

                 

                void uart_0_error_callback(uint32_t id, qm_uart_status_t status)

                {

                  qm_uart_write_buffer(QM_UART_0, (uint8_t *)"*ERROR*\r\n", 10);

                }