debug-uart.c
00001 #include <debug-uart.h>
00002 #include <sys-interrupt.h>
00003
00004 #include <AT91SAM7S64.h>
00005 #include <string.h>
00006 #include <interrupt-utils.h>
00007
00008 #ifndef DBG_XMIT_BUFFER_LEN
00009 #define DBG_XMIT_BUFFER_LEN 3024
00010 #endif
00011 #ifndef DBG_RECV_BUFFER_LEN
00012 #define DBG_RECV_BUFFER_LEN 256
00013 #endif
00014
00015 static unsigned char dbg_xmit_buffer[DBG_XMIT_BUFFER_LEN];
00016 static unsigned char dbg_recv_buffer[DBG_RECV_BUFFER_LEN];
00017 static unsigned int dbg_recv_buffer_len = 0;
00018
00019 void
00020 dbg_setup_uart()
00021 {
00022
00023 *AT91C_PIOA_OER = AT91C_PA10_DTXD;
00024 *AT91C_PIOA_ODR = AT91C_PA9_DRXD;
00025 *AT91C_PIOA_ASR = AT91C_PA10_DTXD | AT91C_PA9_DRXD;
00026 *AT91C_PIOA_PDR = AT91C_PA10_DTXD | AT91C_PA9_DRXD;
00027
00028 *AT91C_DBGU_MR = AT91C_US_PAR_NONE | AT91C_US_CHMODE_NORMAL;
00029 *AT91C_DBGU_IDR= 0xffffffff;
00030
00031 *AT91C_DBGU_BRGR = MCK / (115200 * 16);
00032 *AT91C_DBGU_CR = AT91C_US_RXEN | AT91C_US_TXEN;
00033
00034 *AT91C_DBGU_TPR = (unsigned int)dbg_xmit_buffer;
00035 *AT91C_DBGU_TNPR = (unsigned int)dbg_xmit_buffer;
00036
00037
00038 }
00039
00040 static void (*input_func)(const char *inp, unsigned int len) = NULL;
00041
00042 static int dbg_recv_handler_func()
00043 {
00044 if (!(*AT91C_DBGU_CSR & AT91C_US_RXRDY)) return 0;
00045 unsigned char c = *AT91C_DBGU_RHR;
00046
00047 if (dbg_recv_buffer_len < (DBG_RECV_BUFFER_LEN -1)) {
00048 dbg_recv_buffer[dbg_recv_buffer_len++] = c;
00049 }
00050 if (c == '\n') {
00051 dbg_recv_buffer[dbg_recv_buffer_len] = '\0';
00052 if (input_func) input_func((char*)dbg_recv_buffer, dbg_recv_buffer_len);
00053 dbg_recv_buffer_len = 0;
00054 }
00055 return 1;
00056 }
00057
00058 static SystemInterruptHandler dbg_recv_handler = {NULL, dbg_recv_handler_func};
00059
00060 void
00061 dbg_set_input_handler(void (*handler)(const char *inp, unsigned int len))
00062 {
00063 input_func = handler;
00064 sys_interrupt_append_handler(&dbg_recv_handler);
00065 sys_interrupt_enable();
00066 *AT91C_DBGU_IER = AT91C_US_RXRDY;
00067 }
00068 static volatile unsigned char mutex = 0;
00069
00070 unsigned int
00071 dbg_send_bytes(const unsigned char *seq, unsigned int len)
00072 {
00073 unsigned short next_count;
00074 unsigned short current_count;
00075 unsigned short left;
00076 unsigned int save = disableIRQ();
00077 if (mutex) {
00078 restoreIRQ(save);
00079 return 0;
00080 }
00081 mutex = 1;
00082 *AT91C_DBGU_PTCR =AT91C_PDC_TXTDIS;
00083 while(*AT91C_DBGU_PTSR & AT91C_PDC_TXTEN);
00084 next_count = *AT91C_DBGU_TNCR;
00085 current_count = *AT91C_DBGU_TCR;
00086
00087 left = DBG_XMIT_BUFFER_LEN - next_count - current_count;
00088 if (left > 0) {
00089 if (left < len) len = left;
00090 if (next_count > 0) {
00091
00092 memcpy(&dbg_xmit_buffer[next_count], seq, len);
00093 *AT91C_DBGU_TNCR = next_count + len;
00094 } else {
00095 unsigned char *to = ((unsigned char*)*AT91C_DBGU_TPR) + current_count;
00096 left = &dbg_xmit_buffer[DBG_XMIT_BUFFER_LEN] - to;
00097 if (len > left) {
00098 unsigned int wrapped = len - left;
00099 memcpy(to, seq, left);
00100 memcpy(dbg_xmit_buffer, &seq[left], wrapped);
00101 *AT91C_DBGU_TCR = current_count + left;
00102 *AT91C_DBGU_TNCR = wrapped;
00103 } else {
00104 memcpy(to, seq, len);
00105 *AT91C_DBGU_TCR = current_count + len;
00106 }
00107 }
00108 } else {
00109 len = 0;
00110 }
00111
00112 *AT91C_DBGU_PTCR =AT91C_PDC_TXTEN;
00113 mutex = 0;
00114 restoreIRQ(save);
00115 return len;
00116 }
00117 static unsigned char dbg_write_overrun = 0;
00118
00119 void
00120 dbg_putchar(const char ch)
00121 {
00122 if (dbg_write_overrun) {
00123 if (dbg_send_bytes((const unsigned char*)"^",1) != 1) return;
00124 }
00125 dbg_write_overrun = 0;
00126 if (dbg_send_bytes((const unsigned char*)&ch,1) != 1) {
00127 dbg_write_overrun = 1;
00128 }
00129 }
00130
00131 void
00132 dbg_blocking_putchar(const char ch)
00133 {
00134 if (dbg_write_overrun) {
00135 while (dbg_send_bytes((const unsigned char*)"^",1) != 1);
00136 }
00137 dbg_write_overrun = 0;
00138 while (dbg_send_bytes((const unsigned char*)&ch,1) != 1);
00139 }
00140
00141 #if 0
00142 static StrFormatResult
00143 dbg_write_cb(void *user_data, const char *data, unsigned int len)
00144 {
00145 if (dbg_send_bytes((const unsigned char*)data, len) != len) {
00146 dbg_write_overrun = 1;
00147 return STRFORMAT_FAILED;
00148 }
00149 return STRFORMAT_OK;
00150 }
00151
00152 void
00153 dbg_printf(const char *format, ...)
00154 {
00155 static const StrFormatContext ctxt = {dbg_write_cb, NULL};
00156 va_list ap;
00157 if (dbg_write_overrun) {
00158 if (dbg_send_bytes((const unsigned char*)"^",1) != 1) return;
00159 }
00160 dbg_write_overrun = 0;
00161 va_start(ap, format);
00162 format_str_v(&ctxt, format, ap);
00163 va_end(ap);
00164 }
00165
00166 static StrFormatResult
00167 dbg_write_blocking_cb(void *user_data, const char *data, unsigned int len)
00168 {
00169 unsigned int left = len;
00170 while(left > 0) {
00171 unsigned int sent = dbg_send_bytes((const unsigned char*)data, left);
00172 left -= sent;
00173 data += sent;
00174 }
00175 return STRFORMAT_OK;
00176 }
00177
00178 void
00179 dbg_blocking_printf(const char *format, ...)
00180 {
00181 static const StrFormatContext ctxt = {dbg_write_blocking_cb, NULL};
00182 va_list ap;
00183 if (dbg_write_overrun) {
00184 while (dbg_send_bytes((const unsigned char*)"^",1) != 1);
00185 }
00186 dbg_write_overrun = 0;
00187 va_start(ap, format);
00188 format_str_v(&ctxt, format, ap);
00189 va_end(ap);
00190 }
00191 #endif
00192 void
00193 dbg_drain()
00194 {
00195 while(!(*AT91C_DBGU_CSR & AT91C_US_TXBUFE));
00196 }