- #include <string.h>
- #include "asf.h"
- #include "stdio_serial.h"
- #include "conf_board.h"
- #include "conf_clock.h"
- #include "conf_example.h"
- /** Size of the receive buffer used by the PDC, in bytes. */
- #define BUFFER_SIZE 100
- /** USART PDC transfer type definition. */
- #define PDC_TRANSFER 1
- /** USART FIFO transfer type definition. */
- #define BYTE_TRANSFER 0
- /** Max buffer number. */
- #define MAX_BUF_NUM 1
- /** All interrupt mask. */
- #define ALL_INTERRUPT_MASK 0xffffffff
- /** Timer counter frequency in Hz. */
- #define TC_FREQ 1
- #define STRING_EOL "\r"
- #define STRING_HEADER "-- USART Serial Example --\r\n" \
- "-- "BOARD_NAME" --\r\n" \
- "-- Compiled: "__DATE__" "__TIME__" --"STRING_EOL
- /** Receive buffer. */
- static uint8_t gs_puc_buffer[2][BUFFER_SIZE];
- /** Next Receive buffer. */
- static uint8_t gs_puc_nextbuffer[2][BUFFER_SIZE];
- /** Current bytes in buffer. */
- static uint32_t gs_ul_size_buffer = BUFFER_SIZE;
- /** Current bytes in next buffer. */
- static uint32_t gs_ul_size_nextbuffer = BUFFER_SIZE;
- /** Byte mode read buffer. */
- static uint32_t gs_ul_read_buffer = 0;
- /** Current transfer mode. */
- static uint8_t gs_uc_trans_mode = PDC_TRANSFER;
- /** Buffer number in use. */
- static uint8_t gs_uc_buf_num = 0;
- /** PDC data packet. */
- pdc_packet_t g_st_packet, g_st_nextpacket;
- /** Pointer to PDC register base. */
- Pdc *g_p_pdc;
- /** Flag of one transfer end. */
- static uint8_t g_uc_transend_flag = 0;
- /**
- * \brief Interrupt handler for USART. Echo the bytes received and start the
- * next receive.
- */
- void USART_Handler(void)
- {
- uint32_t ul_status;
- /* Read USART Status. */
- ul_status = usart_get_status(BOARD_USART);
- if (gs_uc_trans_mode == PDC_TRANSFER) {
- /* Receive buffer is full. */
- if (ul_status & US_CSR_RXBUFF) {
- /* Disable timer. */
- tc_stop(TC0, 0);
- /* Echo back buffer. */
- g_st_packet.ul_addr =
- (uint32_t)gs_puc_buffer[gs_uc_buf_num];
- g_st_packet.ul_size = gs_ul_size_buffer;
- g_st_nextpacket.ul_addr =
- (uint32_t)gs_puc_nextbuffer[gs_uc_buf_num];
- g_st_nextpacket.ul_size = gs_ul_size_nextbuffer;
- pdc_tx_init(g_p_pdc, &g_st_packet, &g_st_nextpacket);
- if (g_uc_transend_flag) {
- gs_ul_size_buffer = BUFFER_SIZE;
- gs_ul_size_nextbuffer = BUFFER_SIZE;
- g_uc_transend_flag = 0;
- }
- gs_uc_buf_num = MAX_BUF_NUM - gs_uc_buf_num;
- /* Restart read on buffer. */
- g_st_packet.ul_addr =
- (uint32_t)gs_puc_buffer[gs_uc_buf_num];
- g_st_packet.ul_size = BUFFER_SIZE;
- g_st_nextpacket.ul_addr =
- (uint32_t)gs_puc_nextbuffer[ gs_uc_buf_num];
- g_st_nextpacket.ul_size = BUFFER_SIZE;
- pdc_rx_init(g_p_pdc, &g_st_packet, &g_st_nextpacket);
- /* Restart timer. */
- tc_start(TC0, 0);
- }
- } else {
- /* Transfer without PDC. */
- if (ul_status & US_CSR_RXRDY) {
- usart_getchar(BOARD_USART, (uint32_t *)&gs_ul_read_buffer);
- usart_write(BOARD_USART, gs_ul_read_buffer);
- }
- }
- }
- /**
- * \brief Interrupt handler for TC0. Record the number of bytes received,
- * and then restart a read transfer on the USART if the transfer was stopped.
- */
- void TC0_Handler(void)
- {
- uint32_t ul_status;
- uint32_t ul_byte_total = 0;
- /* Read TC0 Status. */
- ul_status = tc_get_status(TC0, 0);
- /* RC compare. */
- if (((ul_status & TC_SR_CPCS) == TC_SR_CPCS) &&
- (gs_uc_trans_mode == PDC_TRANSFER)) {
- /* Flush PDC buffer. */
- ul_byte_total = BUFFER_SIZE - pdc_read_rx_counter(g_p_pdc);
- if ((ul_byte_total != 0) && (ul_byte_total != BUFFER_SIZE)) {
- /* Log current size. */
- g_uc_transend_flag = 1;
- if (pdc_read_rx_next_counter(g_p_pdc) == 0) {
- gs_ul_size_buffer = BUFFER_SIZE;
- gs_ul_size_nextbuffer = ul_byte_total;
- } else {
- gs_ul_size_buffer = ul_byte_total;
- gs_ul_size_nextbuffer = 0;
- }
- /* Trigger USART Receive Buffer Full Interrupt. */
- pdc_rx_clear_cnt(g_p_pdc);
- }
- }
- }
- /**
- * \brief Configure USART in normal (serial rs232) mode, asynchronous,
- * 8 bits, 1 stop bit, no parity, 115200 bauds and enable its transmitter
- * and receiver.
- */
- static void configure_usart(void)
- {
- const sam_usart_opt_t usart_console_settings = {
- BOARD_USART_BAUDRATE,
- US_MR_CHRL_8_BIT,
- US_MR_PAR_NO,
- US_MR_NBSTOP_1_BIT,
- US_MR_CHMODE_NORMAL,
- /* This field is only used in IrDA mode. */
- 0
- };
- /* Enable the peripheral clock in the PMC. */
- sysclk_enable_peripheral_clock(BOARD_ID_USART);
- /* Configure USART in serial mode. */
- usart_init_rs232(BOARD_USART, &usart_console_settings,
- sysclk_get_cpu_hz());
- /* Disable all the interrupts. */
- usart_disable_interrupt(BOARD_USART, ALL_INTERRUPT_MASK);
- /* Enable the receiver and transmitter. */
- usart_enable_tx(BOARD_USART);
- usart_enable_rx(BOARD_USART);
- /* Configure and enable interrupt of USART. */
- NVIC_EnableIRQ(USART_IRQn);
- }
- /**
- * \brief Configure Timer Counter 0 (TC0) to generate an interrupt every 200ms.
- * This interrupt will be used to flush USART input and echo back.
- */
- static void configure_tc(void)
- {
- uint32_t ul_div;
- uint32_t ul_tcclks;
- static uint32_t ul_sysclk;
- /* Get system clock. */
- ul_sysclk = sysclk_get_cpu_hz();
- /* Configure PMC. */
- pmc_enable_periph_clk(ID_TC0);
- /* Configure TC for a 50Hz frequency and trigger on RC compare. */
- tc_find_mck_divisor(TC_FREQ, ul_sysclk, &ul_div, &ul_tcclks, ul_sysclk);
- tc_init(TC0, 0, ul_tcclks | TC_CMR_CPCTRG);
- tc_write_rc(TC0, 0, (ul_sysclk / ul_div) / TC_FREQ);
- /* Configure and enable interrupt on RC compare. */
- NVIC_EnableIRQ((IRQn_Type)ID_TC0);
- tc_enable_interrupt(TC0, 0, TC_IER_CPCS);
- }
- /**
- * Configure UART for debug message output.
- */
- static void configure_console(void)
- {
- const usart_serial_options_t uart_serial_options = {
- .baudrate = CONF_UART_BAUDRATE,
- .paritytype = CONF_UART_PARITY
- };
- /* Configure console UART. */
- sysclk_enable_peripheral_clock(CONSOLE_UART_ID);
- stdio_serial_init(CONF_UART, &uart_serial_options);
- }
- /**
- * \brief Reset the TX & RX, and clear the PDC counter.
- */
- static void usart_clear(void)
- {
- /* Reset and disable receiver & transmitter. */
- usart_reset_rx(BOARD_USART);
- usart_reset_tx(BOARD_USART);
- /* Clear PDC counter. */
- g_st_packet.ul_addr = 0;
- g_st_packet.ul_size = 0;
- g_st_nextpacket.ul_addr = 0;
- g_st_nextpacket.ul_size = 0;
- pdc_rx_init(g_p_pdc, &g_st_packet, &g_st_nextpacket);
- /* Enable receiver & transmitter. */
- usart_enable_tx(BOARD_USART);
- usart_enable_rx(BOARD_USART);
- }
- /**
- * \brief Display main menu.
- */
- static void display_main_menu(void)
- {
- puts("-- Menu Choices for this example --\r\n"
- "-- s: Switch mode for USART between PDC and without PDC.--\r\n"
- "-- m: Display this menu again.--\r");
- }
- /**
- * \brief Application entry point for usart_serial example.
- *
- * \return Unused (ANSI-C compatibility).
- */
- int main(void)
- {
- uint8_t uc_char;
- uint8_t uc_flag;
- /* Initialize the SAM system. */
- sysclk_init();
- board_init();
- /* Configure UART for debug message output. */
- configure_console();
- /* Output example information. */
- puts(STRING_HEADER);
- /* Configure USART. */
- configure_usart();
- /* Get board USART PDC base address. */
- g_p_pdc = usart_get_pdc_base(BOARD_USART);
- /* Enable receiver and transmitter. */
- pdc_enable_transfer(g_p_pdc, PERIPH_PTCR_RXTEN | PERIPH_PTCR_TXTEN);
- /* Configure TC. */
- configure_tc();
- /* Start receiving data and start timer. */
- g_st_packet.ul_addr = (uint32_t)gs_puc_buffer[gs_uc_buf_num];
- g_st_packet.ul_size = BUFFER_SIZE;
- g_st_nextpacket.ul_addr = (uint32_t)gs_puc_nextbuffer[gs_uc_buf_num];
- g_st_nextpacket.ul_size = BUFFER_SIZE;
- pdc_rx_init(g_p_pdc, &g_st_packet, &g_st_nextpacket);
- puts("-- Start to echo serial inputs -- \r\n"
- "-I- Default Transfer with PDC \r\n"
- "-I- Press 's' to switch transfer mode \r");
- gs_uc_trans_mode = PDC_TRANSFER;
- usart_disable_interrupt(BOARD_USART, US_IDR_RXRDY);
- usart_enable_interrupt(BOARD_USART, US_IER_RXBUFF);
- tc_start(TC0, 0);
- while (1) {
- uc_char = 0;
- uc_flag = uart_read(CONSOLE_UART, &uc_char);
- if (!uc_flag) {
- switch (uc_char) {
- case 's':
- case 'S':
- if (gs_uc_trans_mode == PDC_TRANSFER) {
- /* Transfer to no PDC communication mode. */
- /* Disable PDC controller. */
- pdc_disable_transfer(g_p_pdc,
- PERIPH_PTCR_RXTDIS | PERIPH_PTCR_TXTDIS);
- /* Disable the RXBUFF interrupt. */
- usart_disable_interrupt(BOARD_USART, US_IDR_RXBUFF);
- /* Clear USART controller. */
- usart_clear();
- /* Enable the RXRDY interrupt. */
- usart_enable_interrupt(BOARD_USART, US_IER_RXRDY);
- gs_uc_trans_mode = BYTE_TRANSFER;
- puts("-I- Transfer without PDC \r");
- } else if (gs_uc_trans_mode == BYTE_TRANSFER) {
- pdc_enable_transfer(g_p_pdc,
- PERIPH_PTCR_RXTEN | PERIPH_PTCR_TXTEN);
- /* Clear USART controller. */
- usart_clear();
- /* Reset pdc current buffer size. */
- gs_ul_size_buffer = BUFFER_SIZE;
- gs_ul_size_nextbuffer = BUFFER_SIZE;
- gs_uc_buf_num = 0;
- /* Start receiving data. */
- g_st_packet.ul_addr =
- (uint32_t)gs_puc_buffer[gs_uc_buf_num];
- g_st_packet.ul_size = BUFFER_SIZE;
- g_st_nextpacket.ul_addr =
- (uint32_t)gs_puc_nextbuffer[gs_uc_buf_num];
- g_st_nextpacket.ul_size = BUFFER_SIZE;
- pdc_rx_init(g_p_pdc, &g_st_packet, &g_st_nextpacket);
-
- /* Transfer to PDC communication mode, disable RXRDY interrupt and enable RXBUFF interrupt. */
- usart_disable_interrupt(BOARD_USART, US_IER_RXRDY);
- usart_enable_interrupt(BOARD_USART, US_IER_RXBUFF);
- gs_uc_trans_mode = PDC_TRANSFER;
- puts("-I- Transfer with PDC \r");
- }
- break;
- case 'm':
- case 'M':
- display_main_menu();
- break;
- default:
- break;
- }
- }
- }
- }
至于例程的解析明天再发表。