mirror of
https://github.com/eddyem/stm32samples.git
synced 2026-02-28 03:44:30 +03:00
seems like U[S]ARTS OK, not tested yet
This commit is contained in:
@@ -59,7 +59,7 @@ Inner USB interfaces (IFx):
|
|||||||
| 33 | PB12 | NC | | |
|
| 33 | PB12 | NC | | |
|
||||||
| 34 | PB13 | NC | | |
|
| 34 | PB13 | NC | | |
|
||||||
| 35 | PB14 | USART3 DE | AF7 or PP | RS-485 (1) DE |
|
| 35 | PB14 | USART3 DE | AF7 or PP | RS-485 (1) DE |
|
||||||
| 36 | PB15 | | | |
|
| 36 | PB15 | NC | | |
|
||||||
| 37 | PC6 | NC | | |
|
| 37 | PC6 | NC | | |
|
||||||
| 38 | PC7 | NC | | |
|
| 38 | PC7 | NC | | |
|
||||||
| 39 | PC8 | NC | | |
|
| 39 | PC8 | NC | | |
|
||||||
@@ -118,6 +118,61 @@ DMA2 channels:
|
|||||||
|
|
||||||
UART5 have no DMA channels, so used in interrupts.
|
UART5 have no DMA channels, so used in interrupts.
|
||||||
|
|
||||||
|
You can try to use hardware DE management on two of RS-485, but I decide that as I can't use hardware DE for all three, it would be
|
||||||
|
simpler to use software DE for all.
|
||||||
|
|
||||||
### Sorted by ports (with AF numbers).
|
### Sorted by ports
|
||||||
|
|
||||||
|
| Pin # | Pin name | function | settings | comment |
|
||||||
|
|---------|-------------|-------------|---------------|---------------------|
|
||||||
|
| 14 | PA0 | NC | | |
|
||||||
|
| 15 | PA1 | USART2 DE | AF7 or PP | RS-485 (3) DE |
|
||||||
|
| 16 | PA2 | USART2 TX | AF7 | RS-485 (3) Tx |
|
||||||
|
| 17 | PA3 | USART2 RX | AF7 | RS-485 (3) Rx |
|
||||||
|
| 20 | PA4 | NC | | |
|
||||||
|
| 21 | PA5 | SPI1 SCK | AF5 | SSI CLK |
|
||||||
|
| 22 | PA6 | SPI1 MISO | AF5 | SSI DAT |
|
||||||
|
| 23 | PA7 | NC | | |
|
||||||
|
| 41 | PA8 | NC | | |
|
||||||
|
| 42 | PA9 | (CONF EN) | PU IN | Config jumper |
|
||||||
|
| 43 | PA10 | (USB PU) | PP OUT | USB pullup |
|
||||||
|
| 44 | PA11 | USB DM | AF14 | |
|
||||||
|
| 45 | PA12 | USB DP | AF14 | |
|
||||||
|
| 46 | PA13 | SWDIO | AF0 | |
|
||||||
|
| 49 | PA14 | SWCLK | AF0 | |
|
||||||
|
| 50 | PA15 | NC | | |
|
||||||
|
| 26 | PB0 | (USART1 DE) | PP OUT | RS-485 (2) DE |
|
||||||
|
| 27 | PB1 | NC | | |
|
||||||
|
| 28 | PB2 | NC | | |
|
||||||
|
| 55 | PB3 | NC | | |
|
||||||
|
| 56 | PB4 | NC | | |
|
||||||
|
| 57 | PB5 | NC | | |
|
||||||
|
| 58 | PB6 | NC | | |
|
||||||
|
| 59 | PB7 | NC | | |
|
||||||
|
| 61 | PB8 | CAN RX | AF9 | |
|
||||||
|
| 62 | PB9 | CAN TX | AF9 | |
|
||||||
|
| 29 | PB10 | USART3 TX | AF7 | RS-485 (1) Tx |
|
||||||
|
| 30 | PB11 | USART3 RX | AF7 | RS-485 (1) Rx |
|
||||||
|
| 33 | PB12 | NC | | |
|
||||||
|
| 34 | PB13 | NC | | |
|
||||||
|
| 35 | PB14 | USART3 DE | AF7 or PP | RS-485 (1) DE |
|
||||||
|
| 36 | PB15 | NC | | |
|
||||||
|
| 8 | PC0 | NC | | |
|
||||||
|
| 9 | PC1 | NC | | |
|
||||||
|
| 10 | PC2 | NC | | |
|
||||||
|
| 11 | PC3 | NC | | |
|
||||||
|
| 24 | PC4 | USART1 TX | AF7 | RS-485 (2) Tx |
|
||||||
|
| 25 | PC5 | USART1 RX | AF7 | RS-485 (2) Rx |
|
||||||
|
| 37 | PC6 | NC | | |
|
||||||
|
| 38 | PC7 | NC | | |
|
||||||
|
| 39 | PC8 | NC | | |
|
||||||
|
| 40 | PC9 | NC | | |
|
||||||
|
| 51 | PC10 | UART4 TX | AF5 | RS-232 (1) Tx |
|
||||||
|
| 52 | PC11 | UART4 RX | AF5 | RS-232 (1) Rx |
|
||||||
|
| 53 | PC12 | UART5 TX | AF5 | RS-232(2) / 485 Tx |
|
||||||
|
| 2 | PC13 | NC | | |
|
||||||
|
| 3 | PC14 | NC | | |
|
||||||
|
| 4 | PC15 | NC | | |
|
||||||
|
| 54 | PD2 | UART5 RX | AF5 | RS-232(2) / 485 Rx |
|
||||||
|
| 18 | PF4 | NC | | |
|
||||||
|
|
||||||
|
|||||||
@@ -21,18 +21,61 @@
|
|||||||
uint8_t Config_mode = 0;
|
uint8_t Config_mode = 0;
|
||||||
|
|
||||||
static inline void gpio_setup(){
|
static inline void gpio_setup(){
|
||||||
RCC->AHBENR |= RCC_AHBENR_GPIOAEN | RCC_AHBENR_GPIOBEN | RCC_AHBENR_DMA1EN | RCC_AHBENR_DMA2EN;
|
RCC->AHBENR |= RCC_AHBENR_GPIOAEN | RCC_AHBENR_GPIOBEN | RCC_AHBENR_GPIOCEN | RCC_AHBENR_GPIODEN
|
||||||
|
| RCC_AHBENR_DMA1EN | RCC_AHBENR_DMA2EN;
|
||||||
RCC->APB1ENR |= RCC_APB1ENR_CANEN | RCC_APB1ENR_USART2EN | RCC_APB1ENR_USART3EN
|
RCC->APB1ENR |= RCC_APB1ENR_CANEN | RCC_APB1ENR_USART2EN | RCC_APB1ENR_USART3EN
|
||||||
| RCC_APB1ENR_UART4EN | RCC_APB1ENR_UART5EN;
|
| RCC_APB1ENR_UART4EN | RCC_APB1ENR_UART5EN;
|
||||||
RCC->APB2ENR |= RCC_APB2ENR_USART1EN;
|
RCC->APB2ENR |= RCC_APB2ENR_USART1EN;
|
||||||
for(int i = 0; i < 10000; ++i) nop();
|
for(int i = 0; i < 10000; ++i) nop();
|
||||||
// USB - alternate function 14 @ pins PA11/PA12; SWD - AF0 @PA13/14
|
/********************************************
|
||||||
|
* PA1 * USART2 DE * PP OUT *
|
||||||
|
* PA2 * USART2 TX * AF7 *
|
||||||
|
* PA3 * USART2 RX * AF7 *
|
||||||
|
* PA5 * SPI1 SCK * AF5 *
|
||||||
|
* PA6 * SPI1 MISO * AF5 *
|
||||||
|
* PA9 * (CONF EN) * PU IN *
|
||||||
|
* PA10 * (USB PU) * PP OUT *
|
||||||
|
* PA11 * USB DM * AF14 *
|
||||||
|
* PA12 * USB DP * AF14 *
|
||||||
|
* PA13 * SWDIO * AF0 *
|
||||||
|
* PA14 * SWCLK * AF0 *
|
||||||
|
********************************************/
|
||||||
|
GPIOA->AFR[0] = AFRf(7, 2) | AFRf(7, 3) | AFRf(5, 5) | AFRf(5, 6);
|
||||||
GPIOA->AFR[1] = AFRf(14, 11) | AFRf(14, 12);
|
GPIOA->AFR[1] = AFRf(14, 11) | AFRf(14, 12);
|
||||||
// PA9 - config jumper (PU in), PA10 - USB pullup (PP)
|
GPIOA->MODER = MODER_O(1) | MODER_AF(2) | MODER_AF(3) | MODER_AF(5) | MODER_AF(6) | MODER_I(9) | MODER_O(10)
|
||||||
GPIOA->MODER = MODER_I(9) | MODER_O(10) | MODER_AF(11) | MODER_AF(12) | MODER_AF(13) | MODER_AF(14);
|
| MODER_AF(11) | MODER_AF(12) | MODER_AF(13) | MODER_AF(14);
|
||||||
GPIOA->OSPEEDR = OSPEED_HI(11) | OSPEED_HI(12) | OSPEED_HI(13) | OSPEED_HI(14);
|
GPIOA->OSPEEDR = OSPEED_MED(2) | OSPEED_MED(3) | OSPEED_HI(5) | OSPEED_HI(6)
|
||||||
|
| OSPEED_HI(11) | OSPEED_HI(12) | OSPEED_HI(13) | OSPEED_HI(14);
|
||||||
GPIOA->PUPDR = PUPD_PU(9);
|
GPIOA->PUPDR = PUPD_PU(9);
|
||||||
for(int i = 0; i < 10000; ++i) nop();
|
/********************************************
|
||||||
|
* PB0 * USART1 DE * PP OUT *
|
||||||
|
* PB8 * CAN RX * AF9 *
|
||||||
|
* PB9 * CAN TX * AF9 *
|
||||||
|
* PB10 * USART3 TX * AF7 *
|
||||||
|
* PB11 * USART3 RX * AF7 *
|
||||||
|
* PB14 * USART3 DE * PP OUT *
|
||||||
|
********************************************/
|
||||||
|
GPIOB->AFR[1] = AFRf(9, 8) | AFRf(9, 9) | AFRf(7, 10) | AFRf(7, 11);
|
||||||
|
GPIOB->MODER = MODER_O(0) | MODER_AF(8) | MODER_AF(9) | MODER_AF(10) | MODER_AF(11) | MODER_O(14);
|
||||||
|
GPIOB->OSPEEDR = OSPEED_HI(8) | OSPEED_HI(9) | OSPEED_MED(10) | OSPEED_MED(11);
|
||||||
|
/********************************************
|
||||||
|
* PC4 * USART1 TX * AF7 *
|
||||||
|
* PC5 * USART1 RX * AF7 *
|
||||||
|
* PC10 * UART4 TX * AF5 *
|
||||||
|
* PC11 * UART4 RX * AF5 *
|
||||||
|
* PC12 * UART5 TX * AF5 *
|
||||||
|
********************************************/
|
||||||
|
GPIOC->AFR[0] = AFRf(7, 4) | AFRf(7, 5);
|
||||||
|
GPIOC->AFR[1] = AFRf(5, 10) | AFRf(5, 11) | AFRf(5, 12);
|
||||||
|
GPIOC->MODER = MODER_AF(4) | MODER_AF(5) | MODER_AF(10) | MODER_AF(11) | MODER_AF(12);
|
||||||
|
GPIOC->OSPEEDR = OSPEED_MED(4) | OSPEED_MED(5) | OSPEED_MED(10) | OSPEED_MED(11) | OSPEED_MED(12);
|
||||||
|
/********************************************
|
||||||
|
* PD2 * UART5 RX * AF5 *
|
||||||
|
********************************************/
|
||||||
|
GPIOD->AFR[0] = AFRf(5, 2);
|
||||||
|
GPIOD->MODER = MODER_AF(2);
|
||||||
|
GPIOD->OSPEEDR = OSPEED_MED(2);
|
||||||
|
for(int i = 0; i < 10000; ++i) nop(); // wait a little before reading CFG pin
|
||||||
if(CFG_ON()) Config_mode = 1;
|
if(CFG_ON()) Config_mode = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -29,6 +29,10 @@
|
|||||||
#define CFG_pin (1<<9)
|
#define CFG_pin (1<<9)
|
||||||
#define CFG_ON() (CFG_port->IDR & CFG_pin)
|
#define CFG_ON() (CFG_port->IDR & CFG_pin)
|
||||||
|
|
||||||
|
// RS-485 Rx is low level, Tx - high
|
||||||
|
#define RX485(port, pin) do{port->BRR = pin;}while(0)
|
||||||
|
#define TX485(port, pin) do{port->BSRR = pin;}while(0)
|
||||||
|
|
||||||
extern volatile uint32_t Tms;
|
extern volatile uint32_t Tms;
|
||||||
extern uint8_t Config_mode;
|
extern uint8_t Config_mode;
|
||||||
|
|
||||||
|
|||||||
@@ -15,9 +15,11 @@
|
|||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "flash.h"
|
#include "flash.h"
|
||||||
#include "hardware.h"
|
#include "hardware.h"
|
||||||
#include "proto.h"
|
#include "proto.h"
|
||||||
|
#include "usart.h"
|
||||||
#include "usb_dev.h"
|
#include "usb_dev.h"
|
||||||
|
|
||||||
#define MAXSTRLEN RBINSZ
|
#define MAXSTRLEN RBINSZ
|
||||||
@@ -46,6 +48,7 @@ int main(void){
|
|||||||
while(1){
|
while(1){
|
||||||
// Put here code working WITOUT USB connected
|
// Put here code working WITOUT USB connected
|
||||||
if(!usbON) continue;
|
if(!usbON) continue;
|
||||||
|
usarts_process(); //
|
||||||
for(int i = 0; i < maxno; ++i){ // just echo for first time
|
for(int i = 0; i < maxno; ++i){ // just echo for first time
|
||||||
if(!CDCready[i]) continue;
|
if(!CDCready[i]) continue;
|
||||||
int l = USB_receive(i, (uint8_t*)inbuff, MAXSTRLEN);
|
int l = USB_receive(i, (uint8_t*)inbuff, MAXSTRLEN);
|
||||||
|
|||||||
Binary file not shown.
@@ -23,59 +23,52 @@
|
|||||||
#include "hardware.h"
|
#include "hardware.h"
|
||||||
#include "strfunc.h"
|
#include "strfunc.h"
|
||||||
#include "usart.h"
|
#include "usart.h"
|
||||||
#include "usb_descr.h" // InterfacesAmount, IFx
|
#include "usb_descr.h" // InterfacesAmount, IFx, bufsz
|
||||||
|
#include "usb_dev.h" // get fresh USB input data
|
||||||
|
|
||||||
static volatile int idatalen = 0; // received data line length (including '\n')
|
// !!!!! INDEXED BY INTERFACE NUMBER (just to not check IF6 and IF7) !!!!!
|
||||||
// USARTs registers by interface number [IF1..IF7], index=epNo-1
|
#define USARTSNO 5
|
||||||
static volatile USART_TypeDef *USARTx[InterfacesAmount] = {USART3, USART1, USART2, UART4, UART5, NULL, NULL};
|
|
||||||
static int usartByIfNo[] = {0, ISerial1, ISerial2, ISerial0, ISerial3, ISerial4}; // USARTx -> index x
|
typedef struct {
|
||||||
// APB1/APB2 bus speeds:
|
volatile USART_TypeDef *instance; // U[S]ARTx
|
||||||
static const uint32_t usart_clocks[INTERFACES_AMOUNT] = {
|
uint32_t pclk_freq; // APB1/APB2 frequency
|
||||||
72000000, // USART3 on APB2 (72 MHz)
|
int16_t IRQn; // IRQ number for enable/disable (maybe 0 for DMA-driven channels)
|
||||||
36000000, // USART1 on APB1 (36 MHz)
|
volatile DMA_TypeDef *dma_controller; // DMA1/DMA2 or NULL if not used
|
||||||
72000000, // USART2 on APB2 (72 MHz)
|
volatile DMA_Channel_TypeDef *dma_rx_channel; // e.g., DMA_Channel_5 or NULL if not used
|
||||||
72000000, // UART4 on APB2 (72 MHz)
|
volatile DMA_Channel_TypeDef *dma_tx_channel; // e.g., DMA_Channel_4 or NULL if not used
|
||||||
72000000, // UART5 on APB2 (72 MHz)
|
uint32_t TTCflag; // Tx transfer complete flag
|
||||||
0, // not used
|
uint32_t RTCflag; // Rx transfer complete flag
|
||||||
0 // not used
|
volatile GPIO_TypeDef *DEport; // if RS485 - DE GPIO port (NULL for RS-232 or RS-422)
|
||||||
|
uint32_t DEpin; // -//- pin
|
||||||
|
} USART_Config;
|
||||||
|
|
||||||
|
// IF U[S]ART bus freq TxDMA RxDMA DE (if 485)
|
||||||
|
// maybe DMA1ch2 would be for SPI1Rx (or SSI should be @ SPI3), in this case USART3 would be interrupt-driven
|
||||||
|
// IF1[0]: USART3 APB2 72 MHz DMA1ch2 DMA1ch3 PB14
|
||||||
|
// IF2[1]: USART1 APB1 36 MHz DMA1ch4 DMA1ch5 PB0
|
||||||
|
// IF3[2]: USART2 APB2 72 MHz DMA1ch6 DMA1ch7 PA1
|
||||||
|
// IF4[3]: UART4 APB2 72 MHz DMA2ch5 DMA2ch3
|
||||||
|
// IF5[4]: UART5 APB2 72 MHz - - - interrupt-driven
|
||||||
|
// IF6[5]: (CAN)
|
||||||
|
// IF7[6]: (SPI)
|
||||||
|
static const USART_Config UC[USARTSNO] = {
|
||||||
|
[0] = {.instance = USART3, .pclk_freq = 72000000, USART3_IRQn, .dma_controller = DMA1, .dma_rx_channel = DMA1_Channel3, .dma_tx_channel = DMA1_Channel2, .TTCflag = DMA_ISR_TCIF3, .RTCflag = DMA_ISR_TCIF3, .DEport = GPIOB, .DEpin = 1<<14 },
|
||||||
|
[1] = {.instance = USART1, .pclk_freq = 36000000, USART1_IRQn, .dma_controller = DMA1, .dma_rx_channel = DMA1_Channel5, .dma_tx_channel = DMA1_Channel4, .TTCflag = DMA_ISR_TCIF5, .RTCflag = DMA_ISR_TCIF4, .DEport = GPIOB, .DEpin = 1<<0 },
|
||||||
|
[2] = {.instance = USART2, .pclk_freq = 72000000, USART2_IRQn, .dma_controller = DMA1, .dma_rx_channel = DMA1_Channel6, .dma_tx_channel = DMA1_Channel7, .TTCflag = DMA_ISR_TCIF6, .RTCflag = DMA_ISR_TCIF7, .DEport = GPIOB, .DEpin = 1<<1 },
|
||||||
|
[3] = {.instance = UART4, .pclk_freq = 72000000, UART4_IRQn, .dma_controller = DMA2, .dma_rx_channel = DMA2_Channel3, .dma_tx_channel = DMA2_Channel5, .TTCflag = DMA_ISR_TCIF3, .RTCflag = DMA_ISR_TCIF5 },
|
||||||
|
[4] = {.instance = UART5, .pclk_freq = 72000000, UART5_IRQn }, // no DMA
|
||||||
};
|
};
|
||||||
|
|
||||||
#if 0
|
// buffers for DMA or interrupt-driven data management
|
||||||
volatile int linerdy = 0, // received data ready
|
static uint8_t inbuffers[USARTSNO][DMARXBUFSZ];
|
||||||
dlen = 0, // length of data (including '\n') in current buffer
|
static uint16_t inbufidx[USARTSNO] = {0}; // for interrupt-driven - index of next character (also amount of received bytes)
|
||||||
bufovr = 0; // input buffer overfull
|
static uint8_t outbuffers[USARTSNO][DMATXBUFSZ];
|
||||||
|
static uint16_t outbufidx[USARTSNO] = {0}; // index of next char to transmit over interrupt
|
||||||
|
static uint16_t outbuflen[USARTSNO] = {0}; // length of data to transmit over interrupt [equal 0 if nothing to send]
|
||||||
|
static uint8_t need2send[USARTSNO] = {0}; // flags from IDLE interrupt to send data portion
|
||||||
|
|
||||||
|
// there's no way to tell recipient about overfull, so we will just "eat" spare data!
|
||||||
|
|
||||||
static void usart_putchar(int no, uint8_t ch){
|
|
||||||
while(!(USARTx[no]->ISR & USART_ISR_TXE));
|
|
||||||
USARTx[no]->TDR = ch;
|
|
||||||
}
|
|
||||||
void usart_sendn(uint8_t ifNo, const uint8_t *str, int L){
|
|
||||||
if (!str || L < 0 || ifNo < 1 || ifNo > USARTSNO)
|
|
||||||
return;
|
|
||||||
for(int i = 0; i < L; ++i){
|
|
||||||
usart_putchar(ifNo, str[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// setup all USARTs
|
|
||||||
void usarts_setup(){
|
|
||||||
// clock
|
|
||||||
RCC->APB1ENR |= RCC_APB1ENR_USART2EN | RCC_APB1ENR_USART3EN;
|
|
||||||
RCC->APB2ENR |= RCC_APB2ENR_USART1EN;
|
|
||||||
for(int i = 0; i < USARTSNO; ++i)
|
|
||||||
usart_config(i + USART1_IDX, lineCodings);
|
|
||||||
NVIC_EnableIRQ(USART1_IRQn);
|
|
||||||
NVIC_EnableIRQ(USART2_IRQn);
|
|
||||||
NVIC_EnableIRQ(USART3_IRQn);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// TODO: fixme for different settings
|
|
||||||
//lineCoding.dwDTERate = speeds[usartNo];
|
|
||||||
//lineCoding.bCharFormat = USB_CDC_1_STOP_BITS;
|
|
||||||
//lineCoding.bParityType = USB_CDC_NO_PARITY;
|
|
||||||
//lineCoding.bDataBits = 8;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief usart_config - configure US[A]RT based on usb_LineCoding
|
* @brief usart_config - configure US[A]RT based on usb_LineCoding
|
||||||
@@ -83,9 +76,11 @@ void usarts_setup(){
|
|||||||
* @param lc (io) - linecoding (modified to real speeds)
|
* @param lc (io) - linecoding (modified to real speeds)
|
||||||
*/
|
*/
|
||||||
void usart_config(uint8_t ifNo, usb_LineCoding *lc){
|
void usart_config(uint8_t ifNo, usb_LineCoding *lc){
|
||||||
if(ifNo >= INTERFACES_AMOUNT || USARTx[ifNo] == NULL) return;
|
// all clocking and GPIO config should be done in gpio_setup()!
|
||||||
volatile USART_TypeDef *U = USARTx[ifNo];
|
if(ifNo >= USARTSNO || UC[ifNo].instance == NULL) return;
|
||||||
uint32_t peripheral_clock = usart_clocks[ifNo];
|
const USART_Config *cfg = &UC[ifNo];
|
||||||
|
volatile USART_TypeDef *U = cfg->instance;
|
||||||
|
uint32_t peripheral_clock = cfg->pclk_freq;
|
||||||
// Disable USART while configuring
|
// Disable USART while configuring
|
||||||
U->CR1 = 0;
|
U->CR1 = 0;
|
||||||
U->ICR = 0xFFFFFFFF; // Clear all interrupt flags
|
U->ICR = 0xFFFFFFFF; // Clear all interrupt flags
|
||||||
@@ -118,14 +113,11 @@ void usart_config(uint8_t ifNo, usb_LineCoding *lc){
|
|||||||
}else if(data_bits == 7){
|
}else if(data_bits == 7){
|
||||||
// 7 data + 1 parity = 8 bits total -> M=00 (8-bit mode)
|
// 7 data + 1 parity = 8 bits total -> M=00 (8-bit mode)
|
||||||
// do nothing
|
// do nothing
|
||||||
}else if(data_bits == 8){
|
|
||||||
// 8 data + 1 parity = 9 bits total -> M=01 (9-bit mode)
|
|
||||||
cr1 |= USART_CR1_M0; // M0=1, M1=0
|
|
||||||
}else{
|
}else{
|
||||||
// Unsupported (9 data bits with parity would be 10 bits total)
|
// Unsupported (8 or 9 data bits with parity would be 9/10 bits total)
|
||||||
// Fallback to 8 data + parity
|
// Fallback to 8 data + parity
|
||||||
cr1 |= USART_CR1_M0;
|
cr1 |= USART_CR1_M0;
|
||||||
lc->bDataBits = 8;
|
lc->bDataBits = 8; // ??? need to be tested
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
// Parity disabled
|
// Parity disabled
|
||||||
@@ -133,10 +125,8 @@ void usart_config(uint8_t ifNo, usb_LineCoding *lc){
|
|||||||
cr1 |= USART_CR1_M1; // M1=1, M0=0 -> 7-bit mode
|
cr1 |= USART_CR1_M1; // M1=1, M0=0 -> 7-bit mode
|
||||||
}else if(data_bits == 8){
|
}else if(data_bits == 8){
|
||||||
// do nothing M=00
|
// do nothing M=00
|
||||||
}else if(data_bits == 9){
|
|
||||||
cr1 |= USART_CR1_M0; // M0=1, M1=0 -> 9-bit mode
|
|
||||||
}else{
|
}else{
|
||||||
// Unsupported (5,6 bits) -> fallback to 8 bits
|
// Unsupported (5,6 or bits) -> fallback to 8 bits
|
||||||
lc->bDataBits = 8;
|
lc->bDataBits = 8;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -157,10 +147,37 @@ void usart_config(uint8_t ifNo, usb_LineCoding *lc){
|
|||||||
|
|
||||||
// Write CR2 (stop bits)
|
// Write CR2 (stop bits)
|
||||||
U->CR2 = cr2;
|
U->CR2 = cr2;
|
||||||
// Enable transmitter, receiver, and RX interrupt (optional)
|
// Enable transmitter, receiver, and interrupts (optional)
|
||||||
cr1 |= USART_CR1_TE | USART_CR1_RE | USART_CR1_UE | USART_CR1_RXNEIE;
|
cr1 |= USART_CR1_RE | USART_CR1_UE;
|
||||||
U->CR1 = cr1;
|
if(cfg->DEport){
|
||||||
|
RX485(cfg->DEport, cfg->DEpin);
|
||||||
|
cr1 |= USART_CR1_TCIE;
|
||||||
|
}else cr1 |= USART_CR1_TE;
|
||||||
|
|
||||||
|
// ----- DMA -----
|
||||||
|
if(cfg->dma_controller){ // DMA-driven
|
||||||
|
volatile DMA_Channel_TypeDef *T = cfg->dma_tx_channel, *R = cfg->dma_rx_channel;
|
||||||
|
// Tx DMA
|
||||||
|
T->CCR = 0;
|
||||||
|
T->CPAR = (uint32_t) &U->TDR;
|
||||||
|
T->CCR = DMA_CCR_MINC | DMA_CCR_DIR; // | DMA_CCR_TCIE;
|
||||||
|
// Rx DMA
|
||||||
|
R->CCR = 0;
|
||||||
|
R->CPAR = (uint32_t) &U->RDR;
|
||||||
|
R->CMAR = (uint32_t) inbuffers[ifNo];
|
||||||
|
R->CNDTR = DMARXBUFSZ;
|
||||||
|
R->CCR = DMA_CCR_MINC | DMA_CCR_EN; // | DMA_CCR_TCIE
|
||||||
|
// enable U[S]ART DMA
|
||||||
|
U->CR3 = USART_CR3_DMAT | USART_CR3_DMAR;
|
||||||
|
cr1 |= USART_CR1_IDLEIE; // enable idle interrupt to force small portions of data into ringbuffer
|
||||||
|
}else{
|
||||||
|
cr1 |= USART_CR1_RXNEIE | USART_CR1_TXEIE; // interrupt-driven
|
||||||
|
inbufidx[ifNo] = 0;
|
||||||
|
outbufidx[ifNo] = 0;
|
||||||
|
NVIC_EnableIRQ(cfg->IRQn);
|
||||||
|
}
|
||||||
|
|
||||||
|
U->CR1 = cr1;
|
||||||
// Wait for the idle frame to complete (optional)
|
// Wait for the idle frame to complete (optional)
|
||||||
uint32_t tmout = 16000000;
|
uint32_t tmout = 16000000;
|
||||||
while(!(U->ISR & USART_ISR_TC)){
|
while(!(U->ISR & USART_ISR_TC)){
|
||||||
@@ -169,46 +186,143 @@ void usart_config(uint8_t ifNo, usb_LineCoding *lc){
|
|||||||
U->ICR = 0xFFFFFFFF; // Clear flags again
|
U->ICR = 0xFFFFFFFF; // Clear flags again
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: leave only uart5_exti35_isr, other - over DMA
|
/**
|
||||||
// UART5 [IF5] Tx - over finite-state machine
|
* @brief usart_stop - turn off U[S]ART for given interface
|
||||||
|
* @param ifNo - interface number
|
||||||
/*
|
|
||||||
DMA1 channels:
|
|
||||||
- Ch2: USART3_Tx [IF1]
|
|
||||||
- Ch3: USART3_Rx [IF1]
|
|
||||||
- Ch4: USART1_Tx [IF2]
|
|
||||||
- Ch5: USART1_Rx [IF2]
|
|
||||||
- Ch6: USART2_Rx [IF3]
|
|
||||||
- Ch7: USART2_Tx [IF3]
|
|
||||||
|
|
||||||
DMA2 channels:
|
|
||||||
- Ch3: UART4_Rx [IF4]
|
|
||||||
- Ch5: UART4_Tx [IF4]
|
|
||||||
*/
|
*/
|
||||||
|
void usart_stop(uint8_t ifNo){
|
||||||
|
if(ifNo >= USARTSNO || UC[ifNo].instance == NULL) return;
|
||||||
|
const USART_Config *cfg = &UC[ifNo];
|
||||||
|
cfg->instance->CR1 = 0;
|
||||||
|
if(cfg->DEport) RX485(cfg->DEport, cfg->DEpin);
|
||||||
|
if(cfg->dma_controller){
|
||||||
|
cfg->dma_tx_channel->CCR = 0;
|
||||||
|
cfg->dma_rx_channel->CCR = 0;
|
||||||
|
}else{
|
||||||
|
NVIC_DisableIRQ(cfg->IRQn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void usart_isr(int usartno, volatile USART_TypeDef *U){
|
/**
|
||||||
int iface = usartByIfNo[usartno]; // interface
|
* @brief usarts_process - send/receive processing
|
||||||
if(U->ISR & USART_ISR_RXNE){
|
* Try to send data from output ringbuffer, check input DMA buffer and full input ringbuffer
|
||||||
USB_putbyte(iface, U->RDR);
|
*/
|
||||||
|
void usarts_process(){
|
||||||
|
for(int i = 0; i < USARTSNO; ++i){ // index by interfaces number!!!
|
||||||
|
const USART_Config *cfg = &UC[i];
|
||||||
|
if(!(cfg->instance->CR1 & USART_CR1_UE)) continue; // USART disabled
|
||||||
|
if(cfg->dma_controller){ // DMA-driven
|
||||||
|
// Input data
|
||||||
|
if(DMARXBUFSZ - cfg->dma_rx_channel->CNDTR > DMARXBUFSZ/2 || need2send[i]){
|
||||||
|
volatile DMA_Channel_TypeDef *R = cfg->dma_rx_channel;
|
||||||
|
R->CCR &= ~DMA_CCR_EN; // pause DMA input transactions
|
||||||
|
register int l = DMARXBUFSZ - R->CNDTR;
|
||||||
|
if(l){ // have some input data -> send and restart DMA
|
||||||
|
if(USB_send(i, inbuffers[i], l)){
|
||||||
|
// restart DMA only in case of succesfull sent or if failed, but have ability of buffer overfull
|
||||||
|
R->CMAR = (uint32_t) inbuffers[i];
|
||||||
|
R->CNDTR = DMARXBUFSZ;
|
||||||
|
need2send[i] = 0;
|
||||||
|
if(cfg->DEport) TX485(cfg->DEport, cfg->DEpin);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
R->CCR |= DMA_CCR_EN; // re-enable DMA
|
||||||
|
}
|
||||||
|
// Output data
|
||||||
|
if(cfg->dma_controller->ISR & cfg->RTCflag){ // ready to send new data
|
||||||
|
int got = USB_receive(i, outbuffers[i], DMATXBUFSZ);
|
||||||
|
if(got > 0){ // send next data portion
|
||||||
|
volatile DMA_Channel_TypeDef *T = cfg->dma_tx_channel;
|
||||||
|
cfg->dma_controller->IFCR = cfg->RTCflag; // now we can clear TC flag (TC and CTC are the same)
|
||||||
|
T->CCR &= ~DMA_CCR_EN;
|
||||||
|
T->CMAR = (uint32_t) outbuffers[i];
|
||||||
|
T->CNDTR = got;
|
||||||
|
if(cfg->DEport){ // switch to Tx
|
||||||
|
TX485(cfg->DEport, cfg->DEpin);
|
||||||
|
cfg->instance->CR1 &= ~USART_CR1_RE;
|
||||||
|
cfg->instance->CR1 |= USART_CR1_TE;
|
||||||
|
}
|
||||||
|
T->CCR |= DMA_CCR_EN; // start new transmission
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}else{ // interrupt-driven
|
||||||
|
// Input data
|
||||||
|
volatile USART_TypeDef *U = cfg->instance;
|
||||||
|
U->CR1 &= ~USART_CR1_RXNEIE; // temporarily disable interrupt
|
||||||
|
register int l = inbufidx[i];
|
||||||
|
if(DMARXBUFSZ - l > DMARXBUFSZ/2 || need2send[i]){
|
||||||
|
if(l && USB_send(i, inbuffers[i], l)){
|
||||||
|
need2send[i] = 0;
|
||||||
|
inbufidx[i] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
U->CR1 |= USART_CR1_RXNEIE; // restore irq reaction
|
||||||
|
// output data
|
||||||
|
U->CR1 &= ~USART_CR1_TXEIE;
|
||||||
|
if(outbuflen[i] == 0){
|
||||||
|
int got = USB_receive(i, outbuffers[i], DMATXBUFSZ);
|
||||||
|
if(got > 0){
|
||||||
|
if(cfg->DEport){ // switch to Tx
|
||||||
|
TX485(cfg->DEport, cfg->DEpin);
|
||||||
|
U->CR1 &= ~USART_CR1_RE;
|
||||||
|
U->CR1 |= USART_CR1_TE;
|
||||||
|
}
|
||||||
|
outbufidx[i] = 1; // continue from next symbol
|
||||||
|
outbuflen[i] = got;
|
||||||
|
U->TDR = outbuffers[i][0]; // start transmission
|
||||||
|
}
|
||||||
|
}
|
||||||
|
U->CR1 |= USART_CR1_TXEIE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief usart_isr - U[S]ART interrupt: IDLE (for DMA-driven) or
|
||||||
|
* @param ifno - interface index
|
||||||
|
*/
|
||||||
|
static void usart_isr(uint8_t ifno){
|
||||||
|
const USART_Config *cfg = &UC[ifno];
|
||||||
|
volatile USART_TypeDef *U = cfg->instance;
|
||||||
|
if(U->ISR & USART_ISR_RXNE){ // got new byte
|
||||||
|
if(inbufidx[ifno] == DMARXBUFSZ) (void) U->RDR; // throw away data: buffer overfull
|
||||||
|
else inbuffers[ifno][ inbufidx[ifno]++ ] = U->RDR; // put new byte into buffer
|
||||||
|
}
|
||||||
|
if(U->ISR & USART_ISR_IDLE){ // try to send collected data
|
||||||
|
need2send[ifno] = 1; // seems like data portion is over - try to send it
|
||||||
|
U->ICR = USART_ICR_IDLECF;
|
||||||
|
}
|
||||||
|
if(U->ISR & USART_ISR_TXE){ // send next byte if need
|
||||||
|
if(outbuflen[ifno] < outbufidx[ifno]){
|
||||||
|
U->TDR = outbuffers[ifno][ outbufidx[ifno]++ ];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(U->ISR & USART_ISR_TC){ // switch RS-485 to Rx after transmission complete
|
||||||
|
if(cfg->DEport){
|
||||||
|
RX485(cfg->DEport, cfg->DEpin);
|
||||||
|
U->CR1 &= ~USART_CR1_TE;
|
||||||
|
U->CR1 |= USART_CR1_RE;
|
||||||
|
}
|
||||||
|
U->ICR = USART_ICR_TCCF;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void usart1_exti25_isr(){
|
void usart1_exti25_isr(){
|
||||||
usart_isr(1, USART1);
|
usart_isr(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void usart2_exti26_isr(){
|
void usart2_exti26_isr(){
|
||||||
usart_isr(2, USART2);
|
usart_isr(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
void usart3_exti28_isr(){
|
void usart3_exti28_isr(){
|
||||||
usart_isr(3, USART3);
|
usart_isr(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void uart4_exti34_isr(){
|
void uart4_exti34_isr(){
|
||||||
usart_isr(4, UART4);
|
usart_isr(3);
|
||||||
}
|
}
|
||||||
|
|
||||||
void uart5_exti35_isr(){
|
void uart5_exti35_isr(){
|
||||||
usart_isr(5, UART5);
|
usart_isr(4);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,6 +21,17 @@
|
|||||||
#include "hardware.h"
|
#include "hardware.h"
|
||||||
#include "usb_dev.h"
|
#include "usb_dev.h"
|
||||||
|
|
||||||
void usarts_setup();
|
// DMA linear buffers for Rx/Tx
|
||||||
|
#define DMARXBUFSZ 128
|
||||||
|
#define DMATXBUFSZ 128
|
||||||
|
// ringbuffers for collected data
|
||||||
|
#define USARTRXRBSZ 256
|
||||||
|
#define USARTTXRBSZ 256
|
||||||
|
|
||||||
void usart_config(uint8_t ifNo, usb_LineCoding *lc);
|
void usart_config(uint8_t ifNo, usb_LineCoding *lc);
|
||||||
void usart_sendn(uint8_t ifNo, const uint8_t *str, int L);
|
void usart_stop(uint8_t ifNo);
|
||||||
|
|
||||||
|
void usarts_process();
|
||||||
|
|
||||||
|
int usart_send(uint8_t ifNo, const uint8_t *data, int len);
|
||||||
|
int usart_receive(uint8_t ifNo, uint8_t *data, int len);
|
||||||
|
|||||||
@@ -138,12 +138,14 @@ void clstate_handler(uint8_t ifno, uint16_t val){
|
|||||||
CDCready[ifno] = val; // CONTROL_DTR | CONTROL_RTS -> interface connected; 0 -> disconnected
|
CDCready[ifno] = val; // CONTROL_DTR | CONTROL_RTS -> interface connected; 0 -> disconnected
|
||||||
lastdsz[ifno] = -1;
|
lastdsz[ifno] = -1;
|
||||||
if(val) clearbufs(ifno);
|
if(val) clearbufs(ifno);
|
||||||
|
else usart_stop(ifno); // turn of USART (if it is @ this interface)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SEND_BREAK - disconnect interface and clear its buffers
|
// SEND_BREAK - disconnect interface and clear its buffers
|
||||||
// this is a fake handler as classic CDC ACM never receives this
|
// this is a fake handler as classic CDC ACM never receives this
|
||||||
void break_handler(uint8_t ifno){
|
void break_handler(uint8_t ifno){
|
||||||
CDCready[ifno] = 0;
|
CDCready[ifno] = 0;
|
||||||
|
usart_stop(ifno); // turn of USART (if it is @ this interface)
|
||||||
}
|
}
|
||||||
|
|
||||||
// USB is configured: setup endpoints
|
// USB is configured: setup endpoints
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ void clstate_handler(uint8_t ifno, uint16_t val);
|
|||||||
void linecoding_handler(uint8_t ifno, usb_LineCoding *lc);
|
void linecoding_handler(uint8_t ifno, usb_LineCoding *lc);
|
||||||
|
|
||||||
// as ugly CDC have no BREAK after disconnected client in non-canonical mode, we should use timeout - near 2s
|
// as ugly CDC have no BREAK after disconnected client in non-canonical mode, we should use timeout - near 2s
|
||||||
#define DISCONN_TMOUT (2000)
|
#define DISCONN_TMOUT (2)
|
||||||
|
|
||||||
// sizes of ringbuffers for outgoing and incoming data
|
// sizes of ringbuffers for outgoing and incoming data
|
||||||
#define RBOUTSZ (256)
|
#define RBOUTSZ (256)
|
||||||
|
|||||||
@@ -1,2 +1,2 @@
|
|||||||
#define BUILD_NUMBER "41"
|
#define BUILD_NUMBER "65"
|
||||||
#define BUILD_DATE "2026-02-12"
|
#define BUILD_DATE "2026-02-15"
|
||||||
|
|||||||
Reference in New Issue
Block a user