kdebug_avr.c

Go to the documentation of this file.
00001 
00042 #include "hw/hw_cpu.h"     /* for CLOCK_FREQ */
00043 #include "hw/hw_ser.h"     /* Required for bus macros overrides */
00044 
00045 #include "cfg/cfg_debug.h"
00046 #include <cfg/macros.h> /* for BV(), DIV_ROUND */
00047 
00048 #include <cpu/types.h>
00049 #include <cpu/attr.h>
00050 
00051 #include <avr/io.h>
00052 
00053 #if CONFIG_KDEBUG_PORT == 0
00054 
00055     /*
00056      * Support for special bus policies or external transceivers
00057      * on UART0 (to be overridden in "hw/hw_ser.h").
00058      *
00059      * HACK: if we don't set TXEN, kdbg disables the transmitter
00060      * after each output statement until the serial driver
00061      * is initialized.  These glitches confuse the debug
00062      * terminal that ends up printing some trash.
00063      */
00064     #ifndef KDBG_UART0_BUS_INIT
00065     #define KDBG_UART0_BUS_INIT  do { \
00066             UCR = BV(TXEN0); \
00067         } while (0)
00068     #endif
00069     #ifndef KDBG_UART0_BUS_RX
00070     #define KDBG_UART0_BUS_RX    do {} while (0)
00071     #endif
00072     #ifndef KDBG_UART0_BUS_TX
00073     #define KDBG_UART0_BUS_TX    do {} while (0)
00074     #endif
00075 
00076     #if CPU_AVR_ATMEGA64 || CPU_AVR_ATMEGA128 || CPU_AVR_ATMEGA1281 || CPU_AVR_ATMEGA168
00077         #define UCR UCSR0B
00078         #define UDR UDR0
00079         #define USR UCSR0A
00080     #elif CPU_AVR_ATMEGA8 || CPU_AVR_ATMEGA32
00081         #define UCR    UCSRB
00082         #define USR    UCSRA
00083         #define TXEN0  TXEN
00084         #define UDRE0  UDRE
00085         #define TXC0   TXC
00086         #define TXCIE0 TXCIE
00087         #define UDRIE0 UDRIE
00088     #else
00089         #error Unknown CPU
00090     #endif
00091 
00092     #define KDBG_WAIT_READY()     do { loop_until_bit_is_set(USR, UDRE0); } while(0)
00093     #define KDBG_WAIT_TXDONE()    do { loop_until_bit_is_set(USR, TXC0); } while(0)
00094 
00095     /*
00096      * We must clear the TXC flag before sending a new character to allow
00097      * KDBG_WAIT_TXDONE() to work properly.
00098      *
00099      * BUG: if KDBG_WRITE_CHAR() is called after the TXC flag is set by hardware,
00100      * a new TXC could be generated after we've cleared it and before the new
00101      * character is written to UDR.  On a 485 bus, the transceiver will be put
00102      * in RX mode while still transmitting the last char.
00103      */
00104     #define KDBG_WRITE_CHAR(c)    do { USR |= BV(TXC0); UDR = (c); } while(0)
00105 
00106     #define KDBG_MASK_IRQ(old)    do { \
00107         (old) = UCR; \
00108         UCR |= BV(TXEN0); \
00109         UCR &= ~(BV(TXCIE0) | BV(UDRIE0)); \
00110         KDBG_UART0_BUS_TX; \
00111     } while(0)
00112 
00113     #define KDBG_RESTORE_IRQ(old) do { \
00114         KDBG_WAIT_TXDONE(); \
00115         KDBG_UART0_BUS_RX; \
00116         UCR = (old); \
00117     } while(0)
00118 
00119     typedef uint8_t kdbg_irqsave_t;
00120 
00121 #elif CONFIG_KDEBUG_PORT == 1
00122 
00123     /*
00124         * Support for special bus policies or external transceivers
00125         * on UART1 (to be overridden in "hw/hw_ser.h").
00126         *
00127         * HACK: if we don't set TXEN, kdbg disables the transmitter
00128         * after each output statement until the serial driver
00129         * is initialized.  These glitches confuse the debug
00130         * terminal that ends up printing some trash.
00131         */
00132     #ifndef KDBG_UART1_BUS_INIT
00133     #define KDBG_UART1_BUS_INIT  do { \
00134             UCSR1B = BV(TXEN1); \
00135         } while (0)
00136     #endif
00137     #ifndef KDBG_UART1_BUS_RX
00138     #define KDBG_UART1_BUS_RX    do {} while (0)
00139     #endif
00140     #ifndef KDBG_UART1_BUS_TX
00141     #define KDBG_UART1_BUS_TX    do {} while (0)
00142     #endif
00143 
00144     #define KDBG_WAIT_READY()     do { loop_until_bit_is_set(UCSR1A, UDRE1); } while(0)
00145     #define KDBG_WAIT_TXDONE()    do { loop_until_bit_is_set(UCSR1A, TXC1); } while(0)
00146     #define KDBG_WRITE_CHAR(c)    do { UCSR1A |= BV(TXC1); UDR1 = (c); } while(0)
00147 
00148     #define KDBG_MASK_IRQ(old)    do { \
00149         (old) = UCSR1B; \
00150         UCSR1B |= BV(TXEN1); \
00151         UCSR1B &= ~(BV(TXCIE1) | BV(UDRIE1)); \
00152         KDBG_UART1_BUS_TX; \
00153     } while(0)
00154 
00155     #define KDBG_RESTORE_IRQ(old) do { \
00156         KDBG_WAIT_TXDONE(); \
00157         KDBG_UART1_BUS_RX; \
00158         UCSR1B = (old); \
00159     } while(0)
00160 
00161     typedef uint8_t kdbg_irqsave_t;
00162 
00163 /*
00164  * Special debug port for BitBanged Serial see below for details...
00165  */
00166 #elif CONFIG_KDEBUG_PORT == 666
00167     #include "hw/hw_ser.h"
00168     #define KDBG_WAIT_READY()      do { /*nop*/ } while(0)
00169     #define KDBG_WRITE_CHAR(c)     _kdebug_bitbang_putchar((c))
00170     #define KDBG_MASK_IRQ(old)     do { IRQ_SAVE_DISABLE((old)); } while(0)
00171     #define KDBG_RESTORE_IRQ(old)  do { IRQ_RESTORE((old)); } while(0)
00172     typedef cpu_flags_t kdbg_irqsave_t;
00173 
00174     #define KDBG_DELAY (((CLOCK_FREQ + CONFIG_KDEBUG_BAUDRATE / 2) / CONFIG_KDEBUG_BAUDRATE) + 7) / 14
00175 
00176     static void _kdebug_bitbang_delay(void)
00177     {
00178         unsigned long i;
00179 
00180         for (i = 0; i < KDBG_DELAY; i++)
00181         {
00182             NOP;
00183             NOP;
00184             NOP;
00185             NOP;
00186             NOP;
00187         }
00188     }
00189 
00199     static void _kdebug_bitbang_putchar(char c)
00200     {
00201         int i;
00202         uint16_t data = c;
00203 
00204         /* Add stop bit */
00205         data |= 0x0100;
00206 
00207         /* Add start bit*/
00208         data <<= 1;
00209 
00210         /* Shift out data */
00211         uint16_t shift = 1;
00212         for (i = 0; i < 10; i++)
00213         {
00214             if (data & shift)
00215                 SER_BITBANG_HIGH;
00216             else
00217                 SER_BITBANG_LOW;
00218             _kdebug_bitbang_delay();
00219             shift <<= 1;
00220         }
00221     }
00222 #else
00223     #error CONFIG_KDEBUG_PORT should be either 0, 1 or 666
00224 #endif
00225 
00226 
00227 INLINE void kdbg_hw_init(void)
00228 {
00229     #if CONFIG_KDEBUG_PORT == 666
00230         SER_BITBANG_INIT;
00231     #else /* CONFIG_KDEBUG_PORT != 666 */
00232         /* Compute the baud rate */
00233         uint16_t period = DIV_ROUND(CLOCK_FREQ / 16UL, CONFIG_KDEBUG_BAUDRATE) - 1;
00234 
00235         #if (CPU_AVR_ATMEGA64 || CPU_AVR_ATMEGA128 || CPU_AVR_ATMEGA1281)
00236             #if CONFIG_KDEBUG_PORT == 0
00237                 UBRR0H = (uint8_t)(period>>8);
00238                 UBRR0L = (uint8_t)period;
00239                 KDBG_UART0_BUS_INIT;
00240             #elif CONFIG_KDEBUG_PORT == 1
00241                 UBRR1H = (uint8_t)(period>>8);
00242                 UBRR1L = (uint8_t)period;
00243                 KDBG_UART1_BUS_INIT;
00244             #else
00245                 #error CONFIG_KDEBUG_PORT must be either 0 or 1
00246             #endif
00247 
00248         #elif CPU_AVR_ATMEGA168
00249             UBRR0H = (uint8_t)(period>>8);
00250             UBRR0L = (uint8_t)period;
00251             KDBG_UART0_BUS_INIT;
00252         #elif CPU_AVR_ATMEGA8 || CPU_AVR_ATMEGA32
00253             UBRRH = (uint8_t)(period>>8);
00254             UBRRL = (uint8_t)period;
00255             KDBG_UART0_BUS_INIT;
00256         #elif CPU_AVR_ATMEGA103
00257             UBRR = (uint8_t)period;
00258             KDBG_UART0_BUS_INIT;
00259         #else
00260             #error Unknown CPU
00261         #endif
00262     #endif /* CONFIG_KDEBUG_PORT == 666 */
00263 }
00264