]> rtime.felk.cvut.cz Git - sysless.git/commitdiff
Massive update - fixed buffer overrun resolution, potential race-condition problem...
authorOndrej Spinka <spinkao@fel.cvut.cz>
Wed, 25 Mar 2009 13:21:23 +0000 (14:21 +0100)
committerOndrej Spinka <spinkao@fel.cvut.cz>
Wed, 25 Mar 2009 13:21:23 +0000 (14:21 +0100)
arch/arm/mach-lpc21xx/libs/uart_zen/periph/uart_zen.h
arch/arm/mach-lpc21xx/libs/uart_zen/uart_zen.c

index dee3d38adab63a2492ff292dab33068dec990386..8a271dc1055e0800c626ee3e99c9b8bc48e97f94 100644 (file)
@@ -1,9 +1,9 @@
 /********************************************************/
 /*     ZEN UART library for LPC ARM                    */
 /*                                                     */
-/*             ver. 3.0 release                        */
+/*             ver. 3.3 release                        */
 /*                                                     */
-/* (c) 2006, 2007 Ondrej Spinka, DCE FEE CTU Prague    */
+/* (c) 2006-2009 Ondrej Spinka, DCE FEE CTU Prague     */
 /*                                                     */
 /* no animals were harmed during development/testing   */
 /* of this software product, except the author himself */
@@ -12,6 +12,9 @@
 /* like, safe for satanistic rituals.                  */
 /********************************************************/
 
+#ifndef _UART_ZEN_H
+#define _UART_ZEN_H
+
 #include <types.h>
 #include <lpc21xx.h>
 
 * @{
 */
 
-/*!\def SYSTEM_CLK
-* System clock frequency in Hz.
-*/
-#define SYSTEM_CLK 10000000
-
 /*!\def UART_BUFF_LEN
 * Incomming data buffer length.
 */
-#define UART_BUFF_LEN 64
+#define UART_BUFF_LEN 250
 /*! @} */
 
 /*!\def UART1_OFFSET
 * UART1 number.
 */
 #define UART1 1
+
+/*! @defgroup error_codes Error Codes
+* @ingroup defines
+* Following constants define the error code masks.
+* @{
+*/
+#define ROUND_BUFFER_OVERRUN_ERR_MASK 0x01
+#define RX_BUFFER_OVERRUN_ERR_MASK 0x02
+#define PARITY_ERR_MASK 0x04
+#define FRAME_ERR_MASK 0x08
+#define BREAK_IRQ_ERR_MASK 0x10
+/*! @} */
 /*! @} */
 
 /*! @defgroup prototypes Function Prototypes
 
 /*! UART initialization function.
 * Takes three arguments:
-* \param uart_num unsigned 8-bit int UART device number
+* \param uart_num unsigned 8-bit int UART number (0 or 1)
 * \param baud_rate unsigned 32-bit int baud rate in bps
+* \param pclk unsigned 32-bit int peripheral clock frequency in Hz
 * \param rx_isr_vect unsigned 32-bit int interrupt vector number
 */
-void UART_init ( uint8_t uart_num, uint32_t baud_rate, unsigned rx_isr_vect );
+void UART_init ( uint8_t uart_num, uint32_t baud_rate, uint32_t pclk, unsigned rx_isr_vect );
 
 /*! Data read function.
 * \param uart_num unsigned 8-bit int UART number (0 or 1)
@@ -66,20 +77,23 @@ uint8_t read_UART_data ( uint8_t uart_num );
 
 /*! Determine possible UART transmission errors.
 * \param uart_num unsigned 8-bit int UART number (0 or 1)
-* \return Returns error code (0 no errors, -1 UART error, -2 incoming data buffer overrun).
+* \return Returns error code (0 no errors; bit0 - incoming data buffer overrun, bit1 - overrun error, bit2 - parity error, bit3 - framing error bit4 - break interrupt).
 */
-int8_t UART_test_err ( uint8_t uart_num );
+uint8_t UART_test_err ( uint8_t uart_num );
 
 /*! Determine whether new data wait in the UART round buffer.
 * \param uart_num unsigned 8-bit int UART number (0 or 1)
 * \return Returns 1 if there are unreaded data in the incoming data buffer, 0 otherwise.
 */
-inline uint8_t UART_new_data ( uint8_t uart_num );
+uint8_t UART_new_data ( uint8_t uart_num );
 
 /*! Data write function.
 * Takes two arguments:
 * \param uart_num unsigned 8-bit UART number (0 or 1)
 * \param data unsigned 8-bit int byte (character) to send
+* \return Returns -1 if line was busy and no data were sent, 0 in case of success.
 */
-void write_UART_data ( uint8_t uart_num, uint8_t data );
+int8_t write_UART_data ( uint8_t uart_num, uint8_t data );
 /*! @} */
+
+#endif
\ No newline at end of file
index 590a94b5050a6ab12b1df123600a06b7dc2648d9..0b357d6ff54b7b92d62b52357529d249850aac63 100644 (file)
@@ -1,11 +1,9 @@
 /********************************************************/
 /*     ZEN UART library for LPC ARM                    */
 /*                                                     */
-/*             ver. 3.0 release                        */
+/*             ver. 3.3 release                        */
 /*                                                     */
-/* (c) 2006, 2007 Ondrej Spinka, DCE FEE CTU Prague    */
-/* modified: 2008 Jiri Kubias DCE FEE CTU              */
-/*             - fixed baudrate computing              */
+/* (c) 2006-2009 Ondrej Spinka, DCE FEE CTU Prague     */
 /*                                                     */
 /* no animals were harmed during development/testing   */
 /* of this software product, except the author himself */
@@ -41,8 +39,8 @@
 #define UART_REG_ADDR(base_reg, dev_num) ( *( (volatile char *) ( ( (volatile void *) &base_reg ) + ( (dev_num) * UART1_OFFSET ) ) ) )
 /*! @} */
 
-volatile uint8_t err_flag[2] = {0, 0}, new_data_flag[2] = {0, 0}, over_flag[2] = {0, 0}; //!< UART0 and UART1 error flags, new data flags and buffer overflow flags
-volatile uint8_t i_w[2] = {0, 0}, i_r[2] = {0, 0}; //!< UART0 and UART1 read and write buffer indexes
+volatile uint8_t err_flag[2] = {0, 0}; //!< UART0 and UART1 error flags
+volatile uint16_t write_buffer_index[2] = {0, 0}, read_buffer_index[2] = {0, 0}; //!< UART0 and UART1 read and write buffer indexes
 uint8_t buff[2][UART_BUFF_LEN]; //!< UART0 and UART1 data buffers
 
 /*! UART0 interrupt handler prototype */
@@ -55,48 +53,46 @@ void UART1_irq ( void ) __attribute__ ( ( interrupt ) );
 * \param uart_num unsigned 8-bit int UART number (0 or 1)
 */
 void UART_isr ( uint8_t uart_num ) {
-       if ( i_w[uart_num] > UART_BUFF_LEN - 1 ) i_w[uart_num] = 0; // when buffer is full, start overwriting oldest data
-       
-       err_flag[uart_num] = UART_REG_ADDR ( U0LSR, uart_num ) & 0x8E; // check the line status
+       if ( !( err_flag[uart_num] & 0x1E ) ) err_flag[uart_num] |= UART_REG_ADDR ( U0LSR, uart_num ) & 0x1E; // check the line status
        
        if ( ( UART_REG_ADDR ( U0IIR, uart_num ) & RX_MASK ) == RX_INT ) { // if Rx data ready IRQ is pending
-               buff[uart_num][i_w[uart_num]++] = UART_REG_ADDR ( U0RBR, uart_num ); // store new character into the receive buffer
-               new_data_flag[uart_num] = 1; // set the new data flag
-       }
-       
-       if ( i_w[uart_num] == i_r[uart_num] ) { // when round buffer is full
-               i_r[uart_num]++; // shift the oldest byte pointer
-               over_flag[uart_num] = 1; // set the data overwrite flag
+               buff[uart_num][write_buffer_index[uart_num]] = UART_REG_ADDR ( U0RBR, uart_num ); // store new character into the receive buffer
+               if ( ++write_buffer_index[uart_num] >= UART_BUFF_LEN ) write_buffer_index[uart_num] = 0; // shift the write buffer index
+               
+               if ( write_buffer_index[uart_num] == read_buffer_index[uart_num] ) { // when round buffer is full (overflow condition)
+                       if ( write_buffer_index[uart_num] == 0 ) write_buffer_index[uart_num] = UART_BUFF_LEN - 1; else write_buffer_index[uart_num]--; // shift the write buffer index back
+                       UART_REG_ADDR ( U0IER, uart_num ) = 0x00; // disable Rx interrupt (to prevent new data reception)
+                       err_flag[uart_num] |= 0x01; // set the overflow condition bit in the error flag
+               }
        }
-       
-       VICVectAddr = 0; // int acknowledge
 }
 
 /*! UART0 Rx interrupt service rutine.
 * This rutine might be modified according user demands.
 */
 void UART0_irq ( void ) {
-       UART_isr ( UART0 );
+       UART_isr ( UART0 ); // call UART0 ISR
+       VICVectAddr = 0; // int acknowledge
 }
 
 /*! UART1 Rx interrupt service rutine.
 * This rutine might be modified according user demands.
 */
 void UART1_irq ( void ) {
-       UART_isr ( UART1 );
+       UART_isr ( UART1 ); // call UART1 ISR
+       VICVectAddr = 0; // int acknowledge
 }
 
 /*! UART initialization function.
 * Takes three arguments:
 * \param uart_num unsigned 8-bit int UART number (0 or 1)
 * \param baud_rate unsigned 32-bit int baud rate in bps
+* \param pclk unsigned 32-bit int peripheral clock frequency in Hz
 * \param rx_isr_vect unsigned 32-bit int interrupt vector number
 */
-void UART_init ( uint8_t uart_num, uint32_t baud_rate, unsigned rx_isr_vect ) {
+void UART_init ( uint8_t uart_num, uint32_t baud_rate, uint32_t pclk, unsigned rx_isr_vect ) {
+       uint16_t divisor = ( pclk + ( ( baud_rate * 16 ) / 2 ) ) / ( baud_rate * 16 ); // baud divisor computation
        
-       uint16_t divisor =  (SYSTEM_CLK + (baud_rate * 16)/2) / (baud_rate * 16); // baud divisor computation
-
-
        PINSEL0 &= ( 0xFFFFFFF0 - ( uart_num * 0xEFFF1 ) ); //enable UART functionality on respective processor pins
        PINSEL0 |= ( 0x00000005 + ( uart_num * 0x4FFFB ) );
        UART_REG_ADDR ( U0LCR, uart_num ) = 0x83; // 8-bit data, no parity, set DLAB = 1
@@ -104,11 +100,11 @@ void UART_init ( uint8_t uart_num, uint32_t baud_rate, unsigned rx_isr_vect ) {
        UART_REG_ADDR ( U0DLM, uart_num ) = *( ( (uint8_t *) &divisor ) + 1 ); // write divisor hi-byte
        UART_REG_ADDR ( U0LCR, uart_num ) &= 0x7F; // clear DLAB
        UART_REG_ADDR ( U0FCR, uart_num ) = 0x01; // enable UART FIFO, interrupt level 1 byte - this might be modified by the user
-       UART_REG_ADDR ( U0IER, uart_num ) = 0x01; // enable RBR interrupt
+       UART_REG_ADDR ( U0IER, uart_num ) = 0x01; // enable Rx interrupt
        
        if ( !uart_num ) ( ( uint32_t * ) &VICVectAddr0 )[rx_isr_vect] = ( uint32_t ) UART0_irq; // if UART0 register UART0 interrupt handler
        else ( ( uint32_t * ) &VICVectAddr0 )[rx_isr_vect] = ( uint32_t ) UART1_irq; // else register UART1 interrupt handler
-
+       
        ( ( uint32_t * ) &VICVectCntl0 )[rx_isr_vect] = 0x20 | ( 6 + uart_num ); // enable IRQ slot, set UART interrupt number
        VICIntEnable = ( ( uart_num + 1 ) * 0x00000040 ); //enable UART IRQ
 }
@@ -120,47 +116,46 @@ void UART_init ( uint8_t uart_num, uint32_t baud_rate, unsigned rx_isr_vect ) {
 uint8_t read_UART_data ( uint8_t uart_num ) {
        uint8_t data; // readed data byte
        
-       while ( !new_data_flag[uart_num] ); // wait for new Rx data
+       while ( read_buffer_index[uart_num] == write_buffer_index[uart_num] ); // wait for new Rx data
        
-       if ( i_r[uart_num] > UART_BUFF_LEN - 1 ) i_r[uart_num] = 0; // when top of the buffer is reached, return the read pointer to 0
-       data = buff[uart_num][i_r[uart_num]++]; // read new data from the data buffer
-       if ( i_r[uart_num] == i_w[uart_num] ) new_data_flag[uart_num] = 0; // when all data was read clear the new data flag
+       data = buff[uart_num][read_buffer_index[uart_num]]; // read new data from the data buffer
+       if ( ++read_buffer_index[uart_num] >= UART_BUFF_LEN ) read_buffer_index[uart_num] = 0; // shift the oldest unread byte index
+       
+       if ( ( err_flag[uart_num] & 0x01 ) && ( read_buffer_index[uart_num] == write_buffer_index[uart_num] ) ) { // if in overflow condition and buffer is empty
+               err_flag[uart_num] &= 0xFE; // clear the overflow condition bit
+               UART_REG_ADDR ( U0IER, uart_num ) = 0x01; // enable Rx interrupt (to allow new data reception)
+       }
        
        return data; // return new data byte
 }
 
 /*! Determine possible UART transmission errors.
 * \param uart_num unsigned 8-bit int UART number (0 or 1)
-* \return Returns error code (0 no errors, -1 UART error, -2 incoming data buffer overrun).
+* \return Returns error code (0 no errors; bit0 - incoming data buffer overrun, bit1 - overrun error, bit2 - parity error, bit3 - framing error bit4 - break interrupt).
 */
-int8_t UART_test_err ( uint8_t uart_num ) {
-       if ( err_flag[uart_num] ) { // check the UART0 error flag
-               err_flag[uart_num] = 0; // reset the UART0 error flag
-               return -1; // return error code
-       }
-       
-       if ( over_flag[uart_num] ) { // check the UART0 incoming data buffer overrun flag
-               over_flag[uart_num] = 0; // reset the UART0 incoming data buffer overrun flag
-               return -2; // return error code
-       }
-       
-       return 0; // no errors
+uint8_t UART_test_err ( uint8_t uart_num ) {
+       uint8_t aux = err_flag[uart_num]; // store the error flag into auxiliary variable
+       err_flag[uart_num] &= 0x01; // reset the error flag (but preserve the overflow condition bit)
+       return aux; // return error code
 }
 
 /*! Determine whether new data wait in the UART round buffer.
 * \param uart_num unsigned 8-bit int UART number (0 or 1)
 * \return Returns 1 if there are unreaded data in the incoming data buffer, 0 otherwise.
 */
-inline uint8_t UART_new_data ( uint8_t uart_num ) {
-       return new_data_flag[uart_num]; // return UART new data flag
+uint8_t UART_new_data ( uint8_t uart_num ) {
+       if ( read_buffer_index[uart_num] == write_buffer_index[uart_num] ) return 0; // check whether round buffer is empty
+       else return 1; // if not empty, return 1
 }
 
 /*! Data write function.
 * Takes two arguments:
 * \param uart_num unsigned 8-bit UART number (0 or 1)
 * \param data unsigned 8-bit int byte (character) to send
+* \return Returns -1 if line was busy and no data were sent, 0 in case of success.
 */
-void write_UART_data ( uint8_t uart_num, uint8_t data ) {
-       while ( !( UART_REG_ADDR ( U0LSR, uart_num ) & TX_EMPTY ) ); // wait for the transmitter holding register emptying
+int8_t write_UART_data ( uint8_t uart_num, uint8_t data ) {
+       if ( !( UART_REG_ADDR ( U0LSR, uart_num ) & TX_EMPTY ) ) return -1; // if transmitter holding register is not empty, return -1
        UART_REG_ADDR ( U0THR, uart_num ) = data; // write the data byte to the transmitter holding register
+       return 0; // return success
 }