AIOC/stm32/aioc-fw/Src/usb_serial.c

234 wiersze
8.1 KiB
C
Czysty Zwykły widok Historia

2022-10-20 12:30:14 +00:00
#include "usb_serial.h"
2022-10-20 14:37:32 +00:00
#include "stm32f3xx_hal.h"
#include "aioc.h"
2022-10-20 12:30:14 +00:00
#include "tusb.h"
#include "led.h"
2022-10-20 14:37:32 +00:00
#include "usb_descriptors.h"
2022-10-20 12:30:14 +00:00
2022-10-20 14:37:32 +00:00
void USB_SERIAL_UART_IRQ(void)
{
uint32_t ISR = USB_SERIAL_UART->ISR;
if (ISR & USART_ISR_TXE) {
/* TX register is empty, load up another character */
__disable_irq();
uint32_t available = tud_cdc_n_available(ITF_NUM_CDC_0);
if (available == 0) {
/* No char left in fifo. Disable transmitter and TX-empty interrupt */
USB_SERIAL_UART->CR1 &= (uint32_t) ~(USART_CR1_TE | USART_CR1_TXEIE);
}
__enable_irq();
if (available > 0) {
/* Write char from fifo */
2022-10-20 14:37:32 +00:00
int32_t c = tud_cdc_n_read_char(ITF_NUM_CDC_0);
TU_ASSERT(c != -1, /**/);
2022-10-20 14:37:32 +00:00
USB_SERIAL_UART->TDR = (uint8_t) c;
2022-10-20 20:51:11 +00:00
LED_MODE(1, LED_MODE_FASTPULSE);
2022-10-20 14:37:32 +00:00
}
}
if (ISR & USART_ISR_RXNE) {
/* RX register is not empty, get character and put into USB send buffer */
if (tud_cdc_n_write_available(ITF_NUM_CDC_0) > 0) {
uint8_t c = USB_SERIAL_UART->RDR;
if ( !(USB_SERIAL_UART_GPIO->IDR & (USB_SERIAL_UART_PIN_PTT1 | USB_SERIAL_UART_PIN_PTT2)) ) {
/* Only store character when no PTT is asserted (shares the same pin) */
tud_cdc_n_write(ITF_NUM_CDC_0, &c, 1);
LED_MODE(0, LED_MODE_FASTPULSE);
}
2022-10-20 14:37:32 +00:00
} else {
/* No space in fifo currently. Pause this interrupt and re-enable later */
__disable_irq();
USB_SERIAL_UART->CR1 &= (uint32_t) ~USART_CR1_RXNEIE;
__enable_irq();
}
}
if (ISR & USART_ISR_RTOF) {
USB_SERIAL_UART->ICR = USART_ICR_RTOCF;
/* Receiver timeout. Flush data via USB. */
tud_cdc_n_write_flush(ITF_NUM_CDC_0);
}
2022-10-20 12:30:14 +00:00
2022-10-20 14:37:32 +00:00
if (ISR & USART_ISR_ORE) {
/* Overflow error */
USB_SERIAL_UART->ICR = USART_ICR_ORECF;
TU_ASSERT(0, /**/);
2022-10-20 14:37:32 +00:00
}
if (ISR & USART_ISR_FE) {
USB_SERIAL_UART->ICR = USART_ISR_FE;
}
if (ISR & USART_ISR_NE) {
USB_SERIAL_UART->ICR = USART_ISR_NE;
}
2022-10-20 14:37:32 +00:00
}
// Invoked when CDC interface received data from host
2022-10-20 12:30:14 +00:00
void tud_cdc_rx_cb(uint8_t itf)
{
2022-10-20 14:37:32 +00:00
if (itf == ITF_NUM_CDC_0) {
/* This enables the transmitter and the TX-empty interrupt, which handles writing UART data */
2022-10-20 14:37:32 +00:00
__disable_irq();
USB_SERIAL_UART->CR1 |= USART_CR1_TE | USART_CR1_TXEIE;
2022-10-20 14:37:32 +00:00
__enable_irq();
}
2022-10-20 12:30:14 +00:00
}
2022-10-20 14:37:32 +00:00
// Invoked when space becomes available in TX buffer
void tud_cdc_tx_complete_cb(uint8_t itf)
2022-10-20 12:30:14 +00:00
{
2022-10-20 14:37:32 +00:00
if (itf == ITF_NUM_CDC_0) {
/* Re-enable UART RX-nonempty interrupt to handle reading UART data */
__disable_irq();
USB_SERIAL_UART->CR1 |= USART_CR1_RXNEIE;
__enable_irq();
}
2022-10-20 12:30:14 +00:00
}
2022-10-20 14:37:32 +00:00
// Invoked when line coding is change via SET_LINE_CODING
void tud_cdc_line_coding_cb(uint8_t itf, cdc_line_coding_t const* p_line_coding)
2022-10-20 12:30:14 +00:00
{
2022-10-20 14:37:32 +00:00
if (itf == ITF_NUM_CDC_0) {
/* Disable IRQs and UART */
__disable_irq();
USB_SERIAL_UART->CR1 &= (uint32_t) ~USART_CR1_UE;
/* Calculate new baudrate */
USB_SERIAL_UART->BRR = (HAL_RCCEx_GetPeriphCLKFreq(USB_SERIAL_UART_PERIPHCLK) + p_line_coding->bit_rate/2) / p_line_coding->bit_rate;
if (p_line_coding->data_bits == 8) {
} else {
/* Support only 8 bit character size */
TU_ASSERT(0, /**/);
2022-10-20 14:37:32 +00:00
}
if (p_line_coding->parity == 0) {
/* No parity */
USB_SERIAL_UART->CR1 = (USB_SERIAL_UART->CR1 & (uint32_t) ~(USART_CR1_PCE | USART_CR1_PS | USART_CR1_M | USART_CR1_M0))
| UART_PARITY_NONE;
} else if (p_line_coding->parity == 1) {
/* Odd parity */
USB_SERIAL_UART->CR1 = (USB_SERIAL_UART->CR1 & (uint32_t) ~(USART_CR1_PCE | USART_CR1_PS | USART_CR1_M | USART_CR1_M0))
| UART_PARITY_ODD | UART_WORDLENGTH_9B;
} else if (p_line_coding->parity == 2) {
/* Even parity */
USB_SERIAL_UART->CR1 = (USB_SERIAL_UART->CR1 & (uint32_t) ~(USART_CR1_PCE | USART_CR1_PS | USART_CR1_M | USART_CR1_M0))
| UART_PARITY_EVEN | UART_WORDLENGTH_9B;
} else {
/* Other parity modes are not supported */
TU_ASSERT(0, /**/);
2022-10-20 14:37:32 +00:00
}
if (p_line_coding->stop_bits == 0) {
/* 1 stop bit */
USB_SERIAL_UART->CR2 = (USB_SERIAL_UART->CR2 & (uint32_t) ~USART_CR2_STOP) | UART_STOPBITS_1;
} else if (p_line_coding->stop_bits == 1) {
/* 1.5 stop bit */
USB_SERIAL_UART->CR2 = (USB_SERIAL_UART->CR2 & (uint32_t) ~USART_CR2_STOP) | UART_STOPBITS_1_5;
} else if (p_line_coding->stop_bits == 2) {
/* 2 stop bit */
USB_SERIAL_UART->CR2 = (USB_SERIAL_UART->CR2 & (uint32_t) ~USART_CR2_STOP) | UART_STOPBITS_2;
} else {
/* Other stop bits unsupported */
TU_ASSERT(0, /**/);
2022-10-20 14:37:32 +00:00
}
/* Re-enable UUART and IRQs */
USB_SERIAL_UART->CR1 |= USART_CR1_UE;
__enable_irq();
2022-10-20 12:30:14 +00:00
}
}
2022-10-20 14:37:32 +00:00
// Invoked when cdc when line state changed e.g connected/disconnected
void tud_cdc_line_state_cb(uint8_t itf, bool dtr, bool rts)
2022-10-20 12:30:14 +00:00
{
if (dtr ^ rts) {
/* In case any PTT is asserted, disable UART transmitter due to those sharing the same lines */
__disable_irq();
USB_SERIAL_UART->CR1 &= (uint32_t) ~USART_CR1_TE;
__enable_irq();
}
if (!dtr & rts) {
/* PTT1 */
USB_SERIAL_UART_GPIO->BSRR |= USB_SERIAL_UART_PIN_PTT1;
2022-10-20 20:51:11 +00:00
LED_SET(1, 1);
} else {
USB_SERIAL_UART_GPIO->BRR |= USB_SERIAL_UART_PIN_PTT1;
2022-10-20 20:51:11 +00:00
LED_SET(1, 0);
}
#if AIOC_ENABLE_PTT2
if (dtr & !rts) {
/* PTT2 */
USB_SERIAL_UART_GPIO->BSRR |= USB_SERIAL_UART_PIN_PTT2;
2022-10-20 20:51:11 +00:00
LED_SET(0, 1);
} else {
USB_SERIAL_UART_GPIO->BRR |= USB_SERIAL_UART_PIN_PTT2;
2022-10-20 20:51:11 +00:00
LED_SET(0, 0);
2022-10-20 12:30:14 +00:00
}
#endif
if ( !(dtr ^ rts) ) {
/* Enable UART transmitter again, when no PTT is asserted */
__disable_irq();
USB_SERIAL_UART->CR1 |= USART_CR1_TE;
__enable_irq();
}
2022-10-20 12:30:14 +00:00
}
void USB_SerialInit(void)
{
2022-10-20 14:37:32 +00:00
/* Set up GPIO */
__HAL_RCC_GPIOA_CLK_ENABLE();
GPIO_InitTypeDef SerialGpio;
2022-10-21 14:55:51 +00:00
SerialGpio.Pin = (USB_SERIAL_UART_PIN_TX | USB_SERIAL_UART_PIN_RX);
SerialGpio.Mode = GPIO_MODE_AF_PP;
SerialGpio.Pull = GPIO_PULLUP;
SerialGpio.Speed = GPIO_SPEED_FREQ_LOW;
SerialGpio.Alternate = GPIO_AF7_USART1;
2022-10-21 14:55:51 +00:00
HAL_GPIO_Init(USB_SERIAL_UART_GPIO, &SerialGpio);
/* Set up RTS and DTR controlled GPIOs */
GPIO_InitTypeDef RtsDtrGpio = {
2022-10-21 14:55:51 +00:00
.Pin = (USB_SERIAL_UART_PIN_PTT2 | USB_SERIAL_UART_PIN_PTT1),
.Mode = GPIO_MODE_OUTPUT_PP,
.Pull = GPIO_PULLDOWN,
.Speed = GPIO_SPEED_FREQ_LOW,
.Alternate = 0
};
2022-10-21 14:55:51 +00:00
HAL_GPIO_Init(USB_SERIAL_UART_GPIO, &RtsDtrGpio);
2022-10-20 14:37:32 +00:00
/* Errata 2.11.5 When PCLK is selected as clock source for USART1, PCLK1 is used instead of PCLK2.
* To reach 9 Mbaud, System Clock (SYSCLK) should be selected as USART1 clock source. */
RCC_PeriphCLKInitTypeDef PeriphClk = {
.PeriphClockSelection = RCC_PERIPHCLK_USART1,
.Usart1ClockSelection = RCC_USART1CLKSOURCE_SYSCLK
};
HAL_StatusTypeDef status = HAL_RCCEx_PeriphCLKConfig(&PeriphClk);
TU_ASSERT(status == HAL_OK, /**/);
2022-10-20 14:37:32 +00:00
/* Initialize UART */
__HAL_RCC_USART1_CLK_ENABLE();
USB_SERIAL_UART->CR1 = USART_CR1_RTOIE | UART_OVERSAMPLING_16 | UART_WORDLENGTH_8B
| UART_PARITY_NONE | USART_CR1_RXNEIE | UART_MODE_RX; /* Enable receiver only, transmitter will be enabled on-demand */
2022-10-20 14:37:32 +00:00
USB_SERIAL_UART->CR2 = UART_RECEIVER_TIMEOUT_ENABLE | UART_STOPBITS_1;
USB_SERIAL_UART->CR3 = USART_CR3_EIE;
2022-10-20 14:37:32 +00:00
USB_SERIAL_UART->BRR = (HAL_RCCEx_GetPeriphCLKFreq(USB_SERIAL_UART_PERIPHCLK) + USB_SERIAL_UART_DEFBAUD/2) / USB_SERIAL_UART_DEFBAUD;
USB_SERIAL_UART->RTOR = ((uint32_t) USB_SERIAL_UART_RXTIMEOUT << USART_RTOR_RTO_Pos) & USART_RTOR_RTO_Msk;
USB_SERIAL_UART->CR1 |= USART_CR1_UE;
/* Enable interrupt */
NVIC_SetPriority(ADC1_2_IRQn, AIOC_IRQ_PRIO_SERIAL);
2022-10-20 14:37:32 +00:00
NVIC_EnableIRQ(USART1_IRQn);
2022-10-20 12:30:14 +00:00
}
2022-10-20 14:37:32 +00:00
void USB_SerialTask(void)
2022-10-20 12:30:14 +00:00
{
2022-10-20 14:37:32 +00:00
2022-10-20 12:30:14 +00:00
}