📄 uart.c
字号:
#include "mytypes.h"#include "uart.h"#include "interrupts.h"#include "AT91SAM7.h"#include "byte_fifo.h"#include "aic.h"#define N_UARTS 1#define TX_FIFO_SIZE 64#define RX_FIFO_SIZE 32struct soft_uart {#ifndef UART_POLLED struct byte_fifo tx; struct byte_fifo rx; int transmitting; int sending_break; int tx_total; int rx_total;#endif struct _AT91S_USART *uart;};#ifndef UART_POLLEDstatic U8 tx_buffer[N_UARTS][TX_FIFO_SIZE];static U8 rx_buffer[N_UARTS][RX_FIFO_SIZE];#endifstruct soft_uart uart[N_UARTS];extern void uart_isr_entry_0(void);extern void uart_isr_entry_1(void);intuart_get_byte(U32 u, U8 *b){ int ret_val; int i_state; struct soft_uart *p; volatile struct _AT91S_USART *up; if (u >= N_UARTS) return -1; p = &uart[u]; up = p->uart; i_state = interrupts_get_and_disable();#ifndef UART_POLLED ret_val = byte_fifo_get(&p->rx, b);#else#endif if (i_state) interrupts_enable(); return ret_val;}intuart_put_byte(U32 u, U8 b){ int ret_val; int i_state; struct soft_uart *p; volatile struct _AT91S_USART *up; if (u >= N_UARTS) return -1; p = &uart[u]; up = p->uart; i_state = interrupts_get_and_disable();#ifndef UART_POLLED ret_val = byte_fifo_put(&p->tx, 0, b); /* Enable transmitting and the transmit interrupt. * This will allow the UART tx chain to wake up and * pick up the next byte for tx, if it was stopped. */ p->transmitting = 1; up->US_IER = 0x02;#else# warning Polled UART not supported!#endif if (i_state) interrupts_enable(); return ret_val;}voiduart_put_str(U32 u, const U8 *str){ while (*str) { while (!uart_put_byte(u, *str)) { } str++; }}intuart_set_break(U32 u){ struct soft_uart *p; volatile struct _AT91S_USART *up; if (u >= N_UARTS) return 0; p = &uart[u]; up = p->uart; up->US_CR = 0x200; // set break; p->sending_break = 0; return 1;}intuart_clear_break(U32 u){ struct soft_uart *p; volatile struct _AT91S_USART *up; if (u >= N_UARTS) return 0; p = &uart[u]; up = p->uart; up->US_CR = 0x400; // stop break; p->sending_break = 0; return 1;}#ifndef UART_POLLEDstatic voiduart_process_isr(U32 u){ struct soft_uart *p; volatile struct _AT91S_USART *up; U8 status; U8 b; if (u >= N_UARTS) return; p = &uart[u]; up = p->uart; while (((status = up->US_CSR) & ((p->transmitting) ? 0x03 : 0x01)) != 0) { up->US_CR = 0x100; /* clear error bits */ if (status & 1) { /* Receiver holding. */ b = up->US_RHR; byte_fifo_put(&p->rx, 1, b); p->rx_total++; } if (status & 2) { /* Transmitter empty */ if (byte_fifo_get(&p->tx, &b)) { up->US_THR = b; p->tx_total++; } else { /* Turn off transmitting */ up->US_IDR = 0x02; p->transmitting = 0; } } }}voiduart_isr_C_0(void){ uart_process_isr(0);}voiduart_isr_C_1(void){ uart_process_isr(1);}#endifstatic intuart_calc_divisor(int baudRate){ return (CLOCK_FREQUENCY / baudRate + 8) / 16;}intuart_CheckBreak(U32 u){#if 0 int isBreak; struct soft_uart *p; volatile struct _AT91S_USART *up; if (u >= N_UARTS) return 0; p = &uart[u]; up = p->uart; up->US_CR = 0x100; // clear status flags systimer_WaitMilliseconds(5); isBreak = (up->US_CSR & 4) ? 1 : 0; return isBreak;#else return 0;#endif}intuart_init(U32 u, U32 baudRate, U32 dataBits, U32 stopBits, char parity){ struct soft_uart *p = &uart[u]; volatile struct _AT91S_USART *up; int i_state; U32 peripheral_id; U32 mode; U8 dummy; U32 isr; U32 pinmask = 0; int error = 0; if (u >= N_UARTS) return 0; p = &uart[u]; /* Initialise the uart structure */ switch (u) { case 0: p->uart = AT91C_BASE_US0; peripheral_id = AT91C_PERIPHERAL_ID_US0; pinmask = (1 << 5) | (1 << 6); isr = (U32) uart_isr_entry_0; break; case 1: p->uart = AT91C_BASE_US1; peripheral_id = AT91C_PERIPHERAL_ID_US1; pinmask = (1 << 21) | (1 << 22); // todo isr = (U32) uart_isr_entry_1; break; default: return 0; } byte_fifo_init(&p->tx, &tx_buffer[u][0], TX_FIFO_SIZE); byte_fifo_init(&p->rx, &rx_buffer[u][0], RX_FIFO_SIZE); p->transmitting = 0; up = p->uart; mode = 0; switch (dataBits) { case 7: mode |= 0x80; break; case 8: mode |= 0xc0; break; default: error = 1; } switch (stopBits) { case 1: mode |= 0x00000000; break; case 15: mode |= 0x00001000; break; case 2: mode |= 0x00002000; break; default: error = 1; } switch (parity) { case 'N': mode |= 0x00000800; break; case 'O': mode |= 0x00000200; break; case 'E': mode |= 0x00000000; break; case 'M': mode |= 0x00000600; break; case 'S': mode |= 0x00000400; break; default: error = 1; } if (error) return 0; i_state = interrupts_get_and_disable(); /* Grab the clock we need */ *AT91C_PMC_PCER = (1 << AT91C_PERIPHERAL_ID_PIOA); /* Need PIO too */ *AT91C_PMC_PCER = (1 << peripheral_id); /* Grab the pins we need */ *AT91C_PIOA_PDR = pinmask; *AT91C_PIOA_ASR = pinmask; up->US_CR = 0x5AC; // Disable up->US_MR = mode; up->US_IDR = 0xFFFFFFFF; up->US_BRGR = uart_calc_divisor(baudRate); // rw Baud rate generator up->US_RTOR = 0; // rw Receiver timeout up->US_TTGR = 0; // rw Transmitter time guard up->US_RPR = 0; // rw Receiver pointer up->US_RCR = 0; // rw Receiver counter up->US_TPR = 0; // rw Transmitter pointer up->US_TCR = 0; // rw Transmitter counter // Set up UART interrupt aic_mask_off(peripheral_id); aic_set_vector(peripheral_id, AIC_INT_LEVEL_NORMAL, isr); aic_mask_on(peripheral_id); // Finally enable the UART up->US_CR = 0x50; // enable tx and rx dummy = up->US_RHR; // dummy read. up->US_IER = 1; //Enable rx and tx interrupts. This should cause a bogus tx int if (i_state) interrupts_enable(); return 1;}voiduart_close(U32 u){ /* Nothing */}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -