#include "usart.h" #include "apps.h" #define USART_INTERRUPT_LEVEL 7 #define AT91_BAUD_RATE 115200 volatile AT91PS_PDC pPDC = AT91C_BASE_PDC_US1; volatile AT91PS_USART pUS1 = AT91C_BASE_US1; volatile AT91PS_AIC pAIC = AT91C_BASE_AIC; volatile AT91PS_PIO pPIOA = AT91C_BASE_PIOA; #define usart_rx_ready {(pUS1->US_CSR & AT91C_US_RXRDY)} #define usart_tx_ready {(pUS1->US_CSR & AT91C_US_TXRDY)} void usart_close(void) { // Reset the USART mode pUS1->US_MR = 0; // Reset the baud rate divisor register pUS1->US_BRGR = 0; // Reset the Timeguard Register pUS1->US_TTGR = 0; // Disable all interrupts pUS1->US_IDR = 0xFFFFFFFF; //* Abort the Peripheral Data Transfers //AT91F_PDC_Close((AT91PS_PDC) &(pUSART->US_RPR)); // Disable receiver and transmitter and stop any activity immediately pUS1->US_CR = AT91C_US_TXDIS | AT91C_US_RXDIS | AT91C_US_RSTTX | AT91C_US_RSTRX; } /// Reads data from an USART peripheral, filling the provided buffer until it /// becomes full. This function returns immediately with 1 if the buffer has /// been queued for transmission; otherwise 0. /// \param data Pointer to the buffer where the received data will be stored. /// \param len Size of the data buffer (in bytes). uint8_t usart_readbuffer(uint8_t *data, size_t len) { // Check if the first PDC bank is free if ((pUS1->US_RCR == 0) && (pUS1->US_RNCR == 0)) { pUS1->US_RPR = (uint32_t)data; pUS1->US_RCR = len; pUS1->US_PTCR = AT91C_PDC_RXTEN; return 1; } // Check if the second PDC bank is free else if (pUS1->US_RNCR == 0) { pUS1->US_RNPR = (uint32_t)data; pUS1->US_RNCR = len; return 1; } else { return 0; } } /// Reads and return a packet of data on the specified USART peripheral. This /// function operates asynchronously, so it waits until some data has been /// received. /// \param timeout Time out value (0 -> no timeout). uint8_t usart_read(uint32_t timeout) { if (timeout == 0) { while ((pUS1->US_CSR & AT91C_US_RXRDY) == 0) {}; } else { while ((pUS1->US_CSR & AT91C_US_RXRDY) == 0) { if (timeout == 0) { DbpString("USART_Read: Timed out."); return 0; } timeout--; } } uint8_t res = pUS1->US_RHR; Dbprintf(" usar got %02x", res); return res; } /// Sends one packet of data through the specified USART peripheral. This /// function operates synchronously, so it only returns when the data has been /// actually sent. /// \param data Data to send including 9nth bit and sync field if necessary (in /// the same format as the US_THR register in the datasheet). /// \param timeOut Time out value (0 = no timeout). void usart_write( uint8_t data, uint32_t timeout) { if ( timeout == 0) { while ((pUS1->US_CSR & AT91C_US_TXEMPTY) == 0) {}; } else { while ((pUS1->US_CSR & AT91C_US_TXEMPTY) == 0) { if (timeout == 0) { DbpString("USART_Write: Timed out."); return; } timeout--; } } pUS1->US_THR = data; } uint8_t usart_writebuffer(uint8_t *data, size_t len, uint32_t timeout) { // Check if the first PDC bank is free if ((pUS1->US_TCR == 0) && (pUS1->US_TNCR == 0)) { pUS1->US_TPR = (uint32_t)data; pUS1->US_TCR = len; pUS1->US_PTCR = AT91C_PDC_TXTEN; return 1; } // Check if the second PDC bank is free else if (pUS1->US_TNCR == 0) { pUS1->US_TNPR = (uint32_t)data; pUS1->US_TNCR = len; return 1; } else { return 0; } } // interupt version void Usart_c_irq_handler(void) { // get Usart status register uint32_t status = pUS1->US_CSR; if ( status & AT91C_US_RXRDY){ // Get byte and send pUS1->US_THR = (pUS1->US_RHR & 0x1FF); LED_B_INV(); } // tx if ( status & AT91C_US_TXRDY){ LED_D_INV(); } if ( status & AT91C_US_OVRE) { // clear US_RXRDY (void)(pUS1->US_RHR & 0x1FF); pUS1->US_THR = ('O' & 0x1FF); } // Check error if ( status & AT91C_US_PARE) { pUS1->US_THR = ('P' & 0x1FF); } if ( status & AT91C_US_FRAME) { pUS1->US_THR = ('F' & 0x1FF); } if ( status & AT91C_US_TIMEOUT){ pUS1->US_CR = AT91C_US_STTTO; pUS1->US_THR = ('T' & 0x1FF); } // Reset the status bit pUS1->US_CR = AT91C_US_RSTSTA; } __inline unsigned int AT91F_AIC_ConfigureIt ( AT91PS_AIC pAIC, // \arg pointer to the AIC registers unsigned int irq_id, // \arg interrupt number to initialize unsigned int priority, // \arg priority to give to the interrupt unsigned int src_type, // \arg activation and sense of activation void (*newHandler) (void) ) // \arg address of the interrupt handler { unsigned int oldHandler; unsigned int mask; oldHandler = pAIC->AIC_SVR[irq_id]; mask = (0x1 << irq_id); // Disable the interrupt on the interrupt controller pAIC->AIC_IDCR = mask; // Save the interrupt handler routine pointer and the interrupt priority pAIC->AIC_SVR[irq_id] = (unsigned int) newHandler; // Store the Source Mode Register pAIC->AIC_SMR[irq_id] = (src_type | priority); // Clear the interrupt on the interrupt controller pAIC->AIC_ICCR = mask; return oldHandler; } void usart_init(void) { // disable & reset receiver / transmitter pUS1->US_CR = AT91C_US_RSTRX | AT91C_US_RSTTX | AT91C_US_RXDIS | AT91C_US_TXDIS; //enable the USART 1 Peripheral clock AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_US1); // Configure PIO controllers to peripheral mode A pPIOA->PIO_ASR = (AT91C_PA21_RXD1 | AT91C_PA22_TXD1); // Disable PIO control of the following pins, allows use by the SPI peripheral pPIOA->PIO_PDR = (AT91C_PA21_RXD1 | AT91C_PA22_TXD1); // kill pull-ups // pPIOA->PIO_PPUDR = ~(AT91C_PA21_RXD1 | AT91C_PA22_TXD1); // pPIOA->PIO_MDDR = (AT91C_PA21_RXD1 | AT91C_PA22_TXD1); // Pull-up Enable pPIOA->PIO_PPUER |= (AT91C_PA21_RXD1 | AT91C_PA22_TXD1); // MultiDriver Enable //pPIOA->PIO_MDER |= (AT91C_PA21_RXD1 | AT91C_PA22_TXD1); // Enable the pins to be controlled pPIOA->PIO_PER |= (AT91C_PA21_RXD1 | AT91C_PA22_TXD1); // Configure the pins to be outputs pPIOA->PIO_OER |= (AT91C_PA21_RXD1 | AT91C_PA22_TXD1); //enable PIO in input mode //pPIOA->PIO_ODR = AT91C_PA21_RXD1; // set mode pUS1->US_MR = AT91C_US_USMODE_NORMAL | // normal mode AT91C_US_CLKS_CLOCK | // MCK AT91C_US_CHRL_8_BITS | // 8 bits AT91C_US_PAR_NONE | // parity: none AT91C_US_NBSTOP_1_BIT | // 1 stop bit AT91C_US_CHMODE_NORMAL; // channel mode: normal // baud rate // CD = MCK / (16 * baud) // MCK = 24027428 (pm3 runs on 24MHZ clock PMC_PCKR[0] ) // baudrate 115200 // 16*115200 = 1843200 // 24027428 / 1843200 == 13 --< CD // baudrate 460800 // 16*460800 = 7372800 // 24027428 / 7372800 == 3 pUS1->US_BRGR = 24*1024*1024/(115200*16); // OVER=0 16 // Write the Timeguard Register pUS1->US_TTGR = 0; pUS1->US_RTOR = 0; pUS1->US_FIDI = 0; pUS1->US_IF = 0; // Enable USART IT error and RXRDY // Write to the IER register // pUS1->US_IER = (AT91C_US_TIMEOUT | AT91C_US_FRAME | AT91C_US_OVRE | AT91C_US_RXRDY); // open Usart 1 interrupt /* AT91F_AIC_ConfigureIt( pAIC, AT91C_ID_US1, USART_INTERRUPT_LEVEL, AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL, Usart_c_irq_handler ); */ // enable interupt // pAIC->AIC_IECR = (1 << AT91C_ID_US1); // trigger interrup software // pAIC->AIC_ISCR = (1 << AT91C_ID_US1) ; // enable RX + TX pUS1->US_CR = AT91C_US_RXEN | AT91C_US_TXEN; }