void UART_IRQHandler(struct CB_UART* pctl) { /* Receive */ if ((USART_SR(pctl->iuart) & USART_SR_RXNE) != 0) // Receive reg loaded? { // Here, receive interrupt flag is on. *pctl->rxbuff_in = USART_DR(pctl->iuart);// Read and store char /* Advance pointers to line buffers and array of counts and reset when end reached */ pctl->rxbuff_in = rxbuff_adv(pctl, pctl->rxbuff_in); // Advance pointers common routine } /* Transmit */ if ( (USART_CR1(pctl->iuart) & USART_CR1_TXEIE) != 0) { // Here, yes. Transmit interrupts are enabled so check if a tx interrupt if ( (USART_SR(pctl->iuart) & USART_SR_TXE) != 0) // Transmit register empty? { // Here, yes. USART_DR(pctl->iuart) = *pctl->txbuff_out;// Send next char, step pointer /* Advance output pointer */ pctl->txbuff_out = txbuff_adv(pctl, pctl->txbuff_out); /* Was the last byte loaded the last to send? */ if (pctl->txbuff_out == pctl->txbuff_in) { // Here yes. USART_CR1(pctl->iuart) &= ~USART_CR1_TXEIE; // Disable Tx interrupt } } } return; }
/* * Common USART/UART transmit and receive interrupts are * collated to here. Each serial port simply redirects to here * while passing in its BASE address in peripheral space and the * channel # it has been assigned. The channel number mapping is * established at initialization time. */ void common_usart_isr(uint32_t usart, int channel) { if (USART_SR(usart) & USART_SR_RXNE) { recv_buf[channel][nxt_recv_ndx[channel]] = USART_DR(usart); nxt_recv_ndx[channel] = (nxt_recv_ndx[channel] + 1) % UART_BUF_SIZE; } if (USART_SR(usart) & USART_SR_TXE) { if (nxt_xmit_ndx[channel] == cur_xmit_ndx[channel]) { usart_disable_tx_interrupt(usart); // nothing to send } else { USART_DR(usart) = xmit_buf[channel][cur_xmit_ndx[channel]]; cur_xmit_ndx[channel] = (cur_xmit_ndx[channel] + 1) % UART_BUF_SIZE; } } }
/* For interrupt handling we add a new function which is called * when recieve interrupts happen. The name (usart1_isr) is created * by the irq.json file in libopencm3 calling this interrupt for * USART2 'usart2', adding the suffix '_isr', and then weakly binding * it to the 'do nothing' interrupt function in vec.c. * * By defining it in this file the linker will override that weak * binding and instead bind it here, but you have to get the name * right or it won't work. And you'll wonder where your interrupts * are going. */ void usart1_isr(void) { uint32_t reg; int i; do { reg = USART_SR(CONSOLE_UART); if (reg & USART_SR_RXNE) { recv_buf[recv_ndx_nxt] = USART_DR(CONSOLE_UART); #ifdef RESET_ON_CTRLC /* * This bit of code will jump to the ResetHandler if you * hit ^C */ if (recv_buf[recv_ndx_nxt] == '\003') { scb_reset_system(); return; /* never actually reached */ } #endif /* Check for "overrun" */ i = (recv_ndx_nxt + 1) % RECV_BUF_SIZE; if (i != recv_ndx_cur) { recv_ndx_nxt = i; } } /* can read back-to-back interrupts */ } while ((reg & USART_SR_RXNE) != 0); }
/* * uart_putc(char c) * * Write a character the uart (Blocking). This does what it says, * puts out a character to the serial port. If one is in the process * of being sent it waits until it finishes then puts this one out. */ void uart_putc(char c) { while (!(USART_SR(USART6) & USART_SR_TXE)) { __asm__("NOP"); } USART_DR(USART6) = (uint16_t)(c & 0xff); }
/* * console_putc(char c) * * Send the character 'c' to the USART, wait for the USART * transmit buffer to be empty first. */ void console_putc(char c) { uint32_t reg; do { reg = USART_SR(CONSOLE_UART); } while ((reg & USART_SR_TXE) == 0); USART_DR(CONSOLE_UART) = (uint16_t) c & 0xff; }
bool send_byte(u8 byte) { if(USART_SR(USART) & USART_SR_TXE) { USART_DR(USART) = byte; return true; } return false; }
static bool put_console_char(int8_t c) { int timeout_cnt = 100; /* allow 100msec for USART busy timeout*/ bool ret_stat = false; do { /* check Tx register ready transmissiion */ if(USART_SR(USART3_BASE) & USART_SR_TXE) { USART_DR(USART3_BASE) = c; ret_stat = true; break; } delay_ms(1); /* 1 ms sampling */ } while(--timeout_cnt); return(ret_stat); }
u8 UART_Send(u8 *data, u16 len) { if (busy) return 1; busy = 1; DMA_stream_reset(USART_DMA); dma_set_peripheral_address(USART_DMA.dma, USART_DMA.stream, (u32) &USART_DR(UART_CFG.uart)); /* send data to the USART data register */ dma_set_memory_address(USART_DMA.dma, USART_DMA.stream, (u32) data); dma_set_number_of_data(USART_DMA.dma, USART_DMA.stream, len); dma_set_read_from_memory(USART_DMA.dma, USART_DMA.stream); /* direction is from memory to usart */ dma_enable_memory_increment_mode(USART_DMA.dma, USART_DMA.stream); /* memory pointer increments, peripheral no */ dma_set_peripheral_size(USART_DMA.dma, USART_DMA.stream, DMA_SxCR_PSIZE_8BIT); /* USART_DR is 8bit wide in this mode */ dma_set_memory_size(USART_DMA.dma, USART_DMA.stream, DMA_SxCR_MSIZE_8BIT); /* destination memory is also 8 bit wide */ dma_set_priority(USART_DMA.dma, USART_DMA.stream, DMA_CCR_PL_LOW); dma_enable_transfer_complete_interrupt(USART_DMA.dma, USART_DMA.stream); DMA_channel_select(USART_DMA); DMA_enable_stream(USART_DMA); /* dma ready to go */ usart_enable_tx_dma(UART_CFG.uart); return 0; }
/* * get_console_input() - Gets a character from serial port * * INPUT * - read_char: load pointer with received char data * OUTPUT * true/false update status */ static bool get_console_input(char *read_char) { int timeout_cnt = 100; /* allow 100msec for USART busy timeout*/ bool ret_stat = false; do { /* check Rx register ready for read*/ if(USART_SR(USART3_BASE) & USART_SR_RXNE) { /* data received */ *read_char = USART_DR(USART3_BASE); ret_stat = true; break; } delay_ms(1); /* 1 ms sampling */ } while(--timeout_cnt); return (ret_stat); }
/* For interrupt handling we add a new function which is called * when receive interrupts happen. The name (usart1_isr) is created * by the irq.json file in libopencm3 calling this interrupt for * USART1 'usart1', adding the suffix '_isr', and then weakly binding * it to the 'do nothing' interrupt function in vec.c. * * By defining it in this file the linker will override that weak * binding and instead bind it here, but you have to get the name * right or it won't work. And you'll wonder where your interrupts * are going. */ void usart1_isr(void) { uint32_t reg; int i; do { reg = USART_SR(CONSOLE_UART); if (reg & USART_SR_RXNE) { recv_buf[recv_ndx_nxt] = USART_DR(CONSOLE_UART); #ifdef RESET_ON_CTRLC /* Check for "reset" */ if (recv_buf[recv_ndx_nxt] == '\003') { scb_reset_system(); } #endif /* Check for "overrun" */ i = (recv_ndx_nxt + 1) % RECV_BUF_SIZE; if (i != recv_ndx_cur) { recv_ndx_nxt = i; } } } while ((reg & USART_SR_RXNE) != 0); /* can read back-to-back interrupts */ }
static void console_putc(char c) { while (!(USART_SR(CONSOLE_UART) & USART_SR_TXE)) continue; USART_DR(CONSOLE_UART) = (uint8_t)c; }
u16 usart_recv(u32 usart) { /* Receive data. */ return USART_DR(usart) & USART_DR_MASK; }
void usart_send(u32 usart, u16 data) { /* Send data. */ USART_DR(usart) = (data & USART_DR_MASK); }
OPTL_INLINE uint8_t read() { return USART_DR(base) & USART_DR_MASK; }
OPTL_INLINE void write(uint8_t ch) { USART_DR(base) = ch & USART_DR_MASK; }
void usart_send(uint32_t usart, uint16_t data) { /* Send data. */ USART_DR(usart) = (data & USART_DR_MASK); }
/* * uart_init(tx pin, rx pin, baudrate); * * Initialize a UART that will talk on the tx/rx pin pair at a given baudrate * Curently only 8n1 format, no-hw flow control, only. * * Returns channel unumber (0 - MAX_UART_CHANNELS) or -1 on error */ int uart_init(enum GPIO_PORT_PIN tx, enum GPIO_PORT_PIN rx, int baudrate) { uint32_t my_uart = uart_pin_map(tx, USART); int i; if (uart_pin_map(rx, USART) != my_uart) { /* Both pins are not connected to same serial port */ return -1; } if (nxt_channel >= MAX_UART_CHANNELS) { /* Need more channel configured */ return -2; } if (my_uart == 0) { /* neither pin connects to a USART? */ return -3; } /* Enable Clock for the USART/UART involved */ rcc_peripheral_enable_clock((uint32_t *)uart_pin_map(tx, APB_REG), uart_pin_map(tx, APB_ENA)); /* Enable Clock for the GPIOs we are using */ gpio_enable_clock(tx); gpio_enable_clock(rx); /* GPIO pins */ /* Both AF Mode */ gpio_mode_setup(gpio_base(tx), GPIO_MODE_AF, GPIO_PUPD_NONE, gpio_bit(tx)); gpio_mode_setup(gpio_base(rx), GPIO_MODE_AF, GPIO_PUPD_NONE, gpio_bit(rx)); gpio_set_af(gpio_base(tx), uart_pin_map(tx, AF), gpio_bit(tx)); gpio_set_af(gpio_base(rx), uart_pin_map(rx, AF), gpio_bit(rx)); /* Transmit pin set to an output */ gpio_set_output_options(gpio_base(tx), GPIO_OTYPE_PP, GPIO_OSPEED_25MHZ, gpio_bit(tx)); /* Set up UART parameters */ usart_set_baudrate(my_uart, baudrate); usart_set_databits(my_uart, 8); usart_set_stopbits(my_uart, USART_STOPBITS_1); usart_set_mode(my_uart, USART_MODE_TX_RX); usart_set_parity(my_uart, USART_PARITY_NONE); usart_set_flow_control(my_uart, USART_FLOWCONTROL_NONE); usart_enable(my_uart); nxt_recv_ndx[nxt_channel] = cur_recv_ndx[nxt_channel] = 0; nxt_xmit_ndx[nxt_channel] = cur_xmit_ndx[nxt_channel] = 0; /* * This was done to try to get it to run under GDB with the Black * Magic debug probe but it didn't have any effect (interrupts * are still masked) */ nvic_set_priority(uart_pin_map(tx, IRQ), 0); // highest priority nvic_enable_irq(uart_pin_map(tx, IRQ)); USART_DR(my_uart) = 0; usart_enable_rx_interrupt(my_uart); /* Now create two mappings, channel => usart, and usart => channel */ channel_to_uart_map[nxt_channel] = my_uart; for (i = 0; i < NUARTS; i++) { if (UART_MAP[i] == my_uart) { uart_to_channel_map[i] = nxt_channel; break; } } nxt_channel++; return (nxt_channel - 1); }
uint16_t usart_recv(uint32_t usart) { return USART_DR(usart) & 0xff; }
/* * If we hit this ISR it is because we got a received character * interrupt from the UART. */ void usart6_isr() { recv_buf[buf_ndx++] = USART_DR(USART2); buf_ndx %= RECV_BUFSIZE; }
/* * uart_putc * * This pushes a character into the transmit buffer for * the channel and turns on TX interrupts (which will fire * because initially the register will be empty.) If the * ISR sends out the last character it turns off the transmit * interrupt flag, so that it won't keep firing on an empty * transmit buffer. */ void uart_putc(char c) { while ((USART_SR(USART1) & USART_SR_TXE) == 0); USART_DR(USART1) = c; }
uint16_t usart_recv(uint32_t usart) { /* Receive data. */ return USART_DR(usart) & USART_DR_MASK; }
/** Setup the USART for transmission with DMA. * This function sets up the DMA controller and additional USART parameters for * DMA transmit. The USART must already be configured for normal operation. * * \param s The USART DMA state structure. * \oaram usart The USART base address. * \param dma The DMA controller base address. * \param stream The DMA stream number to use. * \param channel The DMA channel to use. The stream and channel must * correspond to a USART RX channel. */ void usart_tx_dma_setup(usart_tx_dma_state* s, u32 usart, u32 dma, u8 stream, u8 channel) { s->dma = dma; s->usart = usart; s->stream = stream; s->channel = channel; s->byte_counter = 0; s->last_byte_ticks = chTimeNow(); /* Enable clock to DMA peripheral. */ if (dma == DMA1) RCC_AHB1ENR |= RCC_AHB1ENR_DMA1EN; else if (dma == DMA2) RCC_AHB1ENR |= RCC_AHB1ENR_DMA2EN; /* Enable TX DMA on the USART. */ usart_enable_tx_dma(usart); /* Make sure stream is disabled to start. */ DMA_SCR(dma, stream) &= ~DMA_SxCR_EN; /* Configure the DMA controller. */ DMA_SCR(dma, stream) = 0; DMA_SCR(dma, stream) = /* Error interrupts. */ DMA_SxCR_DMEIE | DMA_SxCR_TEIE | /* Transfer complete interrupt. */ DMA_SxCR_TCIE | DMA_SxCR_DIR_MEM_TO_PERIPHERAL | /* Increment the memory address after each transfer. */ DMA_SxCR_MINC | /* 4 bytes written to the FIFO from memory at a time */ DMA_SxCR_MBURST_INCR4 | /* 8 bit transfers from USART peripheral. */ DMA_SxCR_PSIZE_8BIT | /* and to memory. */ DMA_SxCR_MSIZE_8BIT | /* TODO: what priority level is necessary? */ /* Very high priority. */ DMA_SxCR_PL_VERY_HIGH | /* The channel selects which request line will trigger a transfer. * (see CD00225773.pdf Table 23). */ DMA_SxCR_CHSEL(channel); /* For now, don't transfer any number of datas * (will be set in the initiating function). */ DMA_SNDTR(dma, stream) = 0; /* DMA into the USART data register... */ DMA_SPAR(dma, stream) = &USART_DR(usart); /* ...from the TX buffer. */ DMA_SM0AR(dma, stream) = s->buff; /* TODO: Investigate more about the best FIFO settings. */ DMA_SFCR(dma, stream) = DMA_SxFCR_DMDIS | /* Enable DMA stream FIFO. */ DMA_SxFCR_FTH_2_4_FULL | /* Trigger level 2/4 full. */ DMA_SxFCR_FEIE; /* Enable FIFO error interrupt. */ s->wr = s->rd = 0; /* Buffer is empty to begin with. */ /* Enable DMA interrupts for this stream with the NVIC. */ if (dma == DMA1) nvicEnableVector(dma_irq_lookup[0][stream], CORTEX_PRIORITY_MASK(USART_DMA_ISR_PRIORITY)); else if (dma == DMA2) nvicEnableVector(dma_irq_lookup[1][stream], CORTEX_PRIORITY_MASK(USART_DMA_ISR_PRIORITY)); }
/** Setup the USART for receive with DMA. * This function sets up the DMA controller and additional USART parameters for * DMA receive. The USART must already be configured for normal operation. * * \param s The USART DMA state structure. * \oaram usart The USART base address. * \param dma The DMA controller base address. * \param stream The DMA stream number to use. * \param channel The DMA channel to use. The stream and channel must * correspond to a USART RX channel. */ void usart_rx_dma_setup(usart_rx_dma_state* s, u32 usart, u32 dma, u8 stream, u8 channel) { s->dma = dma; s->usart = usart; s->stream = stream; s->channel = channel; chBSemInit(&s->ready_sem, TRUE); s->byte_counter = 0; s->last_byte_ticks = chTimeNow(); /* Enable clock to DMA peripheral. */ if (dma == DMA1) RCC_AHB1ENR |= RCC_AHB1ENR_DMA1EN; else if (dma == DMA2) RCC_AHB1ENR |= RCC_AHB1ENR_DMA2EN; /* Enable RX DMA on the USART. */ usart_enable_rx_dma(usart); /* Make sure stream is disabled to start. */ DMA_SCR(dma, stream) &= ~DMA_SxCR_EN; /* RM0090 - 9.3.17 : Supposed to wait until enable bit reads '0' before we * write to registers. */ while (DMA_SCR(dma, stream) & DMA_SxCR_EN) ; /* RM0090 - 9.3.17 : Supposed to clear any interrupts in DMA status register * before we reconfigure registers. */ dma_clear_interrupt_flags(dma, stream, DMA_ISR_FLAGS); /* Configure the DMA controller. */ DMA_SCR(dma, stream) = 0; DMA_SCR(dma, stream) = /* Error interrupts. */ DMA_SxCR_DMEIE | DMA_SxCR_TEIE | /* Transfer complete interrupt. */ DMA_SxCR_TCIE | /* Enable circular buffer mode. */ DMA_SxCR_CIRC | DMA_SxCR_DIR_PERIPHERAL_TO_MEM | /* Increment the memory address after each transfer. */ DMA_SxCR_MINC | /* 8 bit transfers from USART peripheral. */ DMA_SxCR_PSIZE_8BIT | /* and to memory. */ DMA_SxCR_MSIZE_8BIT | /* Low priority. */ DMA_SxCR_PL_LOW | /* The channel selects which request line will trigger a transfer. * (see CD00225773.pdf Table 23). */ DMA_SxCR_CHSEL(channel); /* Transfer up to the length of the buffer. */ DMA_SNDTR(dma, stream) = USART_RX_BUFFER_LEN; /* DMA from the USART data register... */ DMA_SPAR(dma, stream) = &USART_DR(usart); /* ...to the RX buffer. */ DMA_SM0AR(dma, stream) = s->buff; /* Buffer is empty to begin with. */ s->rd = 0; s->rd_wraps = s->wr_wraps = 0; /* Enable DMA interrupts for this stream with the NVIC. */ if (dma == DMA1) nvicEnableVector(dma_irq_lookup[0][stream], CORTEX_PRIORITY_MASK(USART_DMA_ISR_PRIORITY)); else if (dma == DMA2) nvicEnableVector(dma_irq_lookup[1][stream], CORTEX_PRIORITY_MASK(USART_DMA_ISR_PRIORITY)); /* These reads clear error flags before enabling DMA */ (void)USART_SR(usart); (void)USART_DR(usart); /* Enable the DMA channel. */ DMA_SCR(dma, stream) |= DMA_SxCR_EN; }
void usart_send(uint32_t usart, uint16_t data) { USART_DR(usart) = data; }