mirror of
https://github.com/eddyem/stm32samples.git
synced 2026-02-28 03:44:30 +03:00
almost working U[S]ARTs
This commit is contained in:
@@ -1,37 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is part of the multiiface project.
|
|
||||||
* Copyright 2026 Edward V. Emelianov <edward.emelianoff@gmail.com>.
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "usb_dev.h"
|
|
||||||
|
|
||||||
// debugging messages on config interface
|
|
||||||
|
|
||||||
#ifdef EBUG
|
|
||||||
#define DBG(str) do{USB_sendstr(ICFG, __FILE__ " (L" STR(__LINE__) "): " str); newline(ICFG);}while(0)
|
|
||||||
#define DBGmesg(str) do{USB_sendstr(ICFG, str);}while(0)
|
|
||||||
#define DBGmesgn(str,n) do{USB_send(ICFG, str, n);}while(0)
|
|
||||||
#define DBGnl() newline(ICFG)
|
|
||||||
#else
|
|
||||||
#define DBG(str)
|
|
||||||
#define DBGmesg(str)
|
|
||||||
#define DBGmesgn(str,n)
|
|
||||||
#define DBGnl()
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
@@ -16,6 +16,7 @@
|
|||||||
* 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 "Debug.h"
|
||||||
#include "flash.h"
|
#include "flash.h"
|
||||||
#include "hardware.h"
|
#include "hardware.h"
|
||||||
#include "proto.h"
|
#include "proto.h"
|
||||||
@@ -44,13 +45,14 @@ int main(void){
|
|||||||
USBPU_OFF();
|
USBPU_OFF();
|
||||||
USB_setup();
|
USB_setup();
|
||||||
//uint32_t ctr = Tms;
|
//uint32_t ctr = Tms;
|
||||||
//usb_LineCoding lc = {9600, 0, 0, 8};
|
usb_LineCoding lc = {9600, 0, 0, 8};
|
||||||
//for(int i = 0; i < 5; ++i) usart_config(i, &lc);
|
for(int i = 0; i < 5; ++i) usart_config(i, &lc); // configure all U[S]ARTs for default data
|
||||||
USBPU_ON();
|
USBPU_ON();
|
||||||
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();
|
usarts_process();
|
||||||
|
DBGpri();
|
||||||
/*for(int i = 0; i < 6; ++i){ // just echo for first time
|
/*for(int i = 0; i < 6; ++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.
@@ -1,6 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<!DOCTYPE QtCreatorProject>
|
<!DOCTYPE QtCreatorProject>
|
||||||
<!-- Written by QtCreator 18.0.2, 2026-02-15T23:30:45. -->
|
<!-- Written by QtCreator 18.0.2, 2026-02-16T23:57:09. -->
|
||||||
<qtcreator>
|
<qtcreator>
|
||||||
<data>
|
<data>
|
||||||
<variable>EnvironmentId</variable>
|
<variable>EnvironmentId</variable>
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
debug.h
|
Debug.c
|
||||||
|
Debug.h
|
||||||
flash.c
|
flash.c
|
||||||
flash.h
|
flash.h
|
||||||
hardware.c
|
hardware.c
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
#include <stm32f3.h>
|
#include <stm32f3.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include "debug.h"
|
#include "Debug.h"
|
||||||
#include "hardware.h"
|
#include "hardware.h"
|
||||||
#include "strfunc.h"
|
#include "strfunc.h"
|
||||||
#include "usart.h"
|
#include "usart.h"
|
||||||
@@ -87,6 +87,7 @@ void usart_config(uint8_t ifNo, usb_LineCoding *lc){
|
|||||||
// Assuming oversampling by 16 (default after reset). For higher baud rates you might use by 8.
|
// Assuming oversampling by 16 (default after reset). For higher baud rates you might use by 8.
|
||||||
U->BRR = peripheral_clock / lc->dwDTERate;
|
U->BRR = peripheral_clock / lc->dwDTERate;
|
||||||
lc->dwDTERate = peripheral_clock / U->BRR;
|
lc->dwDTERate = peripheral_clock / U->BRR;
|
||||||
|
DBGs("New speed: "); DBGs(u2str(lc->dwDTERate)); DBGn();
|
||||||
|
|
||||||
// ----- Data bits & Parity -----
|
// ----- Data bits & Parity -----
|
||||||
uint32_t cr1 = 0;
|
uint32_t cr1 = 0;
|
||||||
@@ -102,6 +103,7 @@ void usart_config(uint8_t ifNo, usb_LineCoding *lc){
|
|||||||
lc->bParityType = USB_CDC_EVEN_PARITY;
|
lc->bParityType = USB_CDC_EVEN_PARITY;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
DBGs("Parity: "); DBGch('0'+lc->bParityType); DBGn();
|
||||||
|
|
||||||
// Word length (M bits) depends on data bits and parity
|
// Word length (M bits) depends on data bits and parity
|
||||||
// M[1:0] encoding: 00 = 8 bits, 01 = 9 bits, 10 = 7 bits
|
// M[1:0] encoding: 00 = 8 bits, 01 = 9 bits, 10 = 7 bits
|
||||||
@@ -114,7 +116,7 @@ void usart_config(uint8_t ifNo, usb_LineCoding *lc){
|
|||||||
// 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{
|
}else{
|
||||||
// Unsupported (8 or 9 data bits with parity would be 9/10 bits total)
|
// 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; // ??? need to be tested
|
lc->bDataBits = 8; // ??? need to be tested
|
||||||
@@ -130,6 +132,7 @@ void usart_config(uint8_t ifNo, usb_LineCoding *lc){
|
|||||||
lc->bDataBits = 8;
|
lc->bDataBits = 8;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
DBGs("Data bits: "); DBGch('0' + lc->bDataBits); DBGn();
|
||||||
|
|
||||||
// ----- Stop bits -----
|
// ----- Stop bits -----
|
||||||
uint32_t cr2 = 0;
|
uint32_t cr2 = 0;
|
||||||
@@ -144,18 +147,21 @@ void usart_config(uint8_t ifNo, usb_LineCoding *lc){
|
|||||||
// do nothing: default to 1 stop bit -> CR2=00
|
// do nothing: default to 1 stop bit -> CR2=00
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
DBGs("Stop bits: "); DBGch('0'+lc->bCharFormat); DBGn();
|
||||||
|
|
||||||
// Write CR2 (stop bits)
|
// Write CR2 (stop bits)
|
||||||
U->CR2 = cr2;
|
U->CR2 = cr2;
|
||||||
// Enable transmitter, receiver, and interrupts (optional)
|
// Enable transmitter, receiver, and interrupts (optional)
|
||||||
cr1 |= USART_CR1_RE;
|
cr1 |= USART_CR1_RE | USART_CR1_IDLEIE; // enable idle interrupt to force small portions of data into ringbuffer
|
||||||
if(cfg->DEport){
|
if(cfg->DEport){
|
||||||
|
DBG("485 -> RX");
|
||||||
RX485(cfg->DEport, cfg->DEpin);
|
RX485(cfg->DEport, cfg->DEpin);
|
||||||
cr1 |= USART_CR1_TCIE;
|
cr1 |= USART_CR1_TCIE;
|
||||||
}else cr1 |= USART_CR1_TE;
|
}else cr1 |= USART_CR1_TE;
|
||||||
|
|
||||||
// ----- DMA -----
|
// ----- DMA -----
|
||||||
if(cfg->dma_controller){ // DMA-driven
|
if(cfg->dma_controller){ // DMA-driven
|
||||||
|
DBG("DMA-driven");
|
||||||
volatile DMA_Channel_TypeDef *T = cfg->dma_tx_channel, *R = cfg->dma_rx_channel;
|
volatile DMA_Channel_TypeDef *T = cfg->dma_tx_channel, *R = cfg->dma_rx_channel;
|
||||||
// Tx DMA
|
// Tx DMA
|
||||||
T->CCR = 0;
|
T->CCR = 0;
|
||||||
@@ -169,8 +175,8 @@ void usart_config(uint8_t ifNo, usb_LineCoding *lc){
|
|||||||
R->CCR = DMA_CCR_MINC | DMA_CCR_EN; // | DMA_CCR_TCIE
|
R->CCR = DMA_CCR_MINC | DMA_CCR_EN; // | DMA_CCR_TCIE
|
||||||
// enable U[S]ART DMA
|
// enable U[S]ART DMA
|
||||||
U->CR3 = USART_CR3_DMAT | USART_CR3_DMAR;
|
U->CR3 = USART_CR3_DMAT | USART_CR3_DMAR;
|
||||||
cr1 |= USART_CR1_IDLEIE; // enable idle interrupt to force small portions of data into ringbuffer
|
|
||||||
}else{
|
}else{
|
||||||
|
DBG("IRQ-driven");
|
||||||
cr1 |= USART_CR1_RXNEIE; // interrupt-driven
|
cr1 |= USART_CR1_RXNEIE; // interrupt-driven
|
||||||
inbufidx[ifNo] = 0;
|
inbufidx[ifNo] = 0;
|
||||||
outbufidx[ifNo] = 0;
|
outbufidx[ifNo] = 0;
|
||||||
@@ -183,6 +189,9 @@ void usart_config(uint8_t ifNo, usb_LineCoding *lc){
|
|||||||
if (--tmout == 0) break;
|
if (--tmout == 0) break;
|
||||||
}
|
}
|
||||||
U->ICR = 0xFFFFFFFF; // Clear flags again
|
U->ICR = 0xFFFFFFFF; // Clear flags again
|
||||||
|
TXrdy[ifNo] = 1;
|
||||||
|
DBGch('0' + ifNo);
|
||||||
|
DBG("U[S]ART configured");
|
||||||
}
|
}
|
||||||
|
|
||||||
// start when received DTR
|
// start when received DTR
|
||||||
@@ -192,6 +201,8 @@ void usart_start(uint8_t ifNo){
|
|||||||
cfg->instance->CR1 |= USART_CR1_UE;
|
cfg->instance->CR1 |= USART_CR1_UE;
|
||||||
NVIC_EnableIRQ(cfg->UIRQn);
|
NVIC_EnableIRQ(cfg->UIRQn);
|
||||||
if(cfg->dma_controller) NVIC_EnableIRQ(cfg->DIRQn);
|
if(cfg->dma_controller) NVIC_EnableIRQ(cfg->DIRQn);
|
||||||
|
DBGch('0' + ifNo);
|
||||||
|
DBG("U[S]ART started");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -201,21 +212,16 @@ void usart_start(uint8_t ifNo){
|
|||||||
void usart_stop(uint8_t ifNo){
|
void usart_stop(uint8_t ifNo){
|
||||||
if(ifNo >= USARTSNO || UC[ifNo].instance == NULL) return;
|
if(ifNo >= USARTSNO || UC[ifNo].instance == NULL) return;
|
||||||
const USART_Config *cfg = &UC[ifNo];
|
const USART_Config *cfg = &UC[ifNo];
|
||||||
cfg->instance->CR1 = 0;
|
cfg->instance->CR1 &= ~USART_CR1_UE;
|
||||||
if(cfg->DEport) RX485(cfg->DEport, cfg->DEpin);
|
if(cfg->DEport) RX485(cfg->DEport, cfg->DEpin);
|
||||||
|
/*
|
||||||
if(cfg->dma_controller){
|
if(cfg->dma_controller){
|
||||||
cfg->dma_tx_channel->CCR = 0;
|
|
||||||
cfg->dma_rx_channel->CCR = 0;
|
|
||||||
NVIC_DisableIRQ(cfg->DIRQn);
|
NVIC_DisableIRQ(cfg->DIRQn);
|
||||||
}else{
|
}
|
||||||
NVIC_DisableIRQ(cfg->UIRQn);
|
NVIC_DisableIRQ(cfg->UIRQn);
|
||||||
}
|
*/
|
||||||
}
|
DBGch('0' + ifNo);
|
||||||
|
DBG("U[S]ART stopped");
|
||||||
static void msg(const char *txt, uint8_t ifno, int l){
|
|
||||||
if(!Config_mode) return;
|
|
||||||
CFGWR("IF"); USB_putbyte(ICFG, '1' + ifno); CFGWR(": ");
|
|
||||||
CFGWR(txt); CFGWR(" ("); CFGWR(i2str(l)); CFGWR(" bytes)\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -234,12 +240,11 @@ void usarts_process(){
|
|||||||
register int l = DMARXBUFSZ - R->CNDTR;
|
register int l = DMARXBUFSZ - R->CNDTR;
|
||||||
if(l){ // have some input data -> send and restart DMA
|
if(l){ // have some input data -> send and restart DMA
|
||||||
if(USB_send(i, inbuffers[i], l)){
|
if(USB_send(i, inbuffers[i], l)){
|
||||||
msg("USART -> USB over DMA", i, l);
|
DBG("USART -> USB over DMA");
|
||||||
// restart DMA only in case of succesfull sent or if failed, but have ability of buffer overfull
|
// restart DMA only in case of succesfull sent or if failed, but have ability of buffer overfull
|
||||||
R->CMAR = (uint32_t) inbuffers[i];
|
R->CMAR = (uint32_t) inbuffers[i];
|
||||||
R->CNDTR = DMARXBUFSZ;
|
R->CNDTR = DMARXBUFSZ;
|
||||||
need2send[i] = 0;
|
need2send[i] = 0;
|
||||||
if(cfg->DEport) TX485(cfg->DEport, cfg->DEpin);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
R->CCR |= DMA_CCR_EN; // re-enable DMA
|
R->CCR |= DMA_CCR_EN; // re-enable DMA
|
||||||
@@ -254,13 +259,14 @@ void usarts_process(){
|
|||||||
T->CMAR = (uint32_t) outbuffers[i];
|
T->CMAR = (uint32_t) outbuffers[i];
|
||||||
T->CNDTR = got;
|
T->CNDTR = got;
|
||||||
if(cfg->DEport){ // switch to Tx
|
if(cfg->DEport){ // switch to Tx
|
||||||
|
DBG("485 -> TX");
|
||||||
TX485(cfg->DEport, cfg->DEpin);
|
TX485(cfg->DEport, cfg->DEpin);
|
||||||
cfg->instance->CR1 &= ~USART_CR1_RE;
|
cfg->instance->CR1 &= ~USART_CR1_RE;
|
||||||
cfg->instance->CR1 |= USART_CR1_TE;
|
cfg->instance->CR1 |= USART_CR1_TE;
|
||||||
}
|
}
|
||||||
T->CCR |= DMA_CCR_EN; // start new transmission
|
|
||||||
TXrdy[i] = 0;
|
TXrdy[i] = 0;
|
||||||
msg("USB -> USART over DMA", i, got);
|
T->CCR |= DMA_CCR_EN; // start new transmission
|
||||||
|
DBG("USB -> USART over DMA");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}else{ // interrupt-driven
|
}else{ // interrupt-driven
|
||||||
@@ -272,7 +278,7 @@ void usarts_process(){
|
|||||||
if(l && USB_send(i, inbuffers[i], l)){
|
if(l && USB_send(i, inbuffers[i], l)){
|
||||||
need2send[i] = 0;
|
need2send[i] = 0;
|
||||||
inbufidx[i] = 0;
|
inbufidx[i] = 0;
|
||||||
msg("USART -> USB over irq", i, l);
|
DBG("USART -> USB over irq");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
U->CR1 |= USART_CR1_RXNEIE; // restore irq reaction
|
U->CR1 |= USART_CR1_RXNEIE; // restore irq reaction
|
||||||
@@ -281,6 +287,7 @@ void usarts_process(){
|
|||||||
int got = USB_receive(i, outbuffers[i], DMATXBUFSZ);
|
int got = USB_receive(i, outbuffers[i], DMATXBUFSZ);
|
||||||
if(got > 0){
|
if(got > 0){
|
||||||
if(cfg->DEport){ // switch to Tx
|
if(cfg->DEport){ // switch to Tx
|
||||||
|
DBG("485 -> TX");
|
||||||
TX485(cfg->DEport, cfg->DEpin);
|
TX485(cfg->DEport, cfg->DEpin);
|
||||||
U->CR1 &= ~USART_CR1_RE;
|
U->CR1 &= ~USART_CR1_RE;
|
||||||
U->CR1 |= USART_CR1_TE;
|
U->CR1 |= USART_CR1_TE;
|
||||||
@@ -290,7 +297,7 @@ void usarts_process(){
|
|||||||
TXrdy[i] = 0;
|
TXrdy[i] = 0;
|
||||||
U->TDR = outbuffers[i][0]; // start transmission
|
U->TDR = outbuffers[i][0]; // start transmission
|
||||||
U->CR1 |= USART_CR1_TXEIE; // enable TXE interrupt
|
U->CR1 |= USART_CR1_TXEIE; // enable TXE interrupt
|
||||||
msg("USB -> USART over irq", i, got);
|
DBG("USB -> USART over irq");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -300,8 +307,8 @@ void usarts_process(){
|
|||||||
// Use this function only for debug purpose
|
// Use this function only for debug purpose
|
||||||
int usart_send(uint8_t ifNo, const uint8_t *data, int len){
|
int usart_send(uint8_t ifNo, const uint8_t *data, int len){
|
||||||
if(ifNo >= USARTSNO || !data || len < 1) return 0;
|
if(ifNo >= USARTSNO || !data || len < 1) return 0;
|
||||||
if(TXrdy[ifNo] == 0) return -1; // busy
|
|
||||||
const USART_Config *cfg = &UC[ifNo];
|
const USART_Config *cfg = &UC[ifNo];
|
||||||
|
if(TXrdy[ifNo] == 0 || (!cfg->instance->CR1 & USART_CR1_UE)) return -1; // busy or not active
|
||||||
if(len > DMATXBUFSZ) len = DMATXBUFSZ;
|
if(len > DMATXBUFSZ) len = DMATXBUFSZ;
|
||||||
memcpy(outbuffers[ifNo], data, len);
|
memcpy(outbuffers[ifNo], data, len);
|
||||||
if(cfg->dma_controller){
|
if(cfg->dma_controller){
|
||||||
@@ -311,15 +318,17 @@ int usart_send(uint8_t ifNo, const uint8_t *data, int len){
|
|||||||
T->CMAR = (uint32_t) outbuffers[ifNo];
|
T->CMAR = (uint32_t) outbuffers[ifNo];
|
||||||
T->CNDTR = len;
|
T->CNDTR = len;
|
||||||
if(cfg->DEport){ // switch to Tx
|
if(cfg->DEport){ // switch to Tx
|
||||||
|
DBG("485 -> TX");
|
||||||
TX485(cfg->DEport, cfg->DEpin);
|
TX485(cfg->DEport, cfg->DEpin);
|
||||||
cfg->instance->CR1 &= ~USART_CR1_RE;
|
cfg->instance->CR1 &= ~USART_CR1_RE;
|
||||||
cfg->instance->CR1 |= USART_CR1_TE;
|
cfg->instance->CR1 |= USART_CR1_TE;
|
||||||
}
|
}
|
||||||
T->CCR |= DMA_CCR_EN; // start new transmission
|
|
||||||
TXrdy[ifNo] = 0;
|
TXrdy[ifNo] = 0;
|
||||||
|
T->CCR |= DMA_CCR_EN; // start new transmission
|
||||||
}else{
|
}else{
|
||||||
volatile USART_TypeDef *U = cfg->instance;
|
volatile USART_TypeDef *U = cfg->instance;
|
||||||
if(cfg->DEport){ // switch to Tx
|
if(cfg->DEport){ // switch to Tx
|
||||||
|
DBG("485 -> TX");
|
||||||
TX485(cfg->DEport, cfg->DEpin);
|
TX485(cfg->DEport, cfg->DEpin);
|
||||||
U->CR1 &= ~USART_CR1_RE;
|
U->CR1 &= ~USART_CR1_RE;
|
||||||
U->CR1 |= USART_CR1_TE;
|
U->CR1 |= USART_CR1_TE;
|
||||||
@@ -339,24 +348,32 @@ int usart_send(uint8_t ifNo, const uint8_t *data, int len){
|
|||||||
static void usart_isr(uint8_t ifno){
|
static void usart_isr(uint8_t ifno){
|
||||||
const USART_Config *cfg = &UC[ifno];
|
const USART_Config *cfg = &UC[ifno];
|
||||||
volatile USART_TypeDef *U = cfg->instance;
|
volatile USART_TypeDef *U = cfg->instance;
|
||||||
if(U->ISR & USART_ISR_RXNE){ // got new byte
|
// for every flag we should also check if it's IRQ active
|
||||||
|
if((U->ISR & USART_ISR_RXNE) && (U->CR1 & USART_CR1_RXNEIE)){ // got new byte
|
||||||
|
DBG("RXNE");
|
||||||
if(inbufidx[ifno] == DMARXBUFSZ) (void) U->RDR; // throw away data: buffer overfull
|
if(inbufidx[ifno] == DMARXBUFSZ) (void) U->RDR; // throw away data: buffer overfull
|
||||||
else inbuffers[ifno][ inbufidx[ifno]++ ] = U->RDR; // put new byte into buffer
|
else inbuffers[ifno][ inbufidx[ifno]++ ] = U->RDR; // put new byte into buffer
|
||||||
}
|
}
|
||||||
if(U->ISR & USART_ISR_IDLE){ // try to send collected data
|
// IDLE active for both DMA- and interrupt-driven transitions
|
||||||
|
if(U->ISR & USART_ISR_IDLE){ // try to send collected data (DMA-driven)
|
||||||
need2send[ifno] = 1; // seems like data portion is over - try to send it
|
need2send[ifno] = 1; // seems like data portion is over - try to send it
|
||||||
U->ICR = USART_ICR_IDLECF;
|
U->ICR = USART_ICR_IDLECF;
|
||||||
|
DBG("IDLE");
|
||||||
}
|
}
|
||||||
if(U->ISR & USART_ISR_TXE){ // send next byte if need
|
if((U->ISR & USART_ISR_TXE) && (U->CR1 & USART_CR1_TXEIE)){ // send next byte if need (interrupt-driven)
|
||||||
|
DBG("TXE");
|
||||||
if(outbuflen[ifno] > outbufidx[ifno]){
|
if(outbuflen[ifno] > outbufidx[ifno]){
|
||||||
U->TDR = outbuffers[ifno][ outbufidx[ifno]++ ];
|
U->TDR = outbuffers[ifno][ outbufidx[ifno]++ ];
|
||||||
}else{
|
}else if(U->CR1 & USART_CR1_TXEIE){
|
||||||
U->CR1 &= ~USART_CR1_TXEIE; // disable interrupt: no data to send
|
U->CR1 &= ~USART_CR1_TXEIE; // disable interrupt: no data to send
|
||||||
TXrdy[ifno] = 1;
|
TXrdy[ifno] = 1;
|
||||||
|
DBG("TXRDY");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(U->ISR & USART_ISR_TC){ // switch RS-485 to Rx after transmission complete
|
if(U->ISR & USART_ISR_TC){ // switch RS-485 to Rx after transmission complete
|
||||||
|
DBG("TC");
|
||||||
if(cfg->DEport){
|
if(cfg->DEport){
|
||||||
|
DBG("485 -> RX");
|
||||||
RX485(cfg->DEport, cfg->DEpin);
|
RX485(cfg->DEport, cfg->DEpin);
|
||||||
U->CR1 &= ~USART_CR1_TE;
|
U->CR1 &= ~USART_CR1_TE;
|
||||||
U->CR1 |= USART_CR1_RE;
|
U->CR1 |= USART_CR1_RE;
|
||||||
@@ -373,7 +390,7 @@ void uart4_exti34_isr(){ usart_isr(3); }
|
|||||||
void uart5_exti35_isr(){ usart_isr(4); }
|
void uart5_exti35_isr(){ usart_isr(4); }
|
||||||
|
|
||||||
// DMA Tx interrupts (to arm ready flag)
|
// DMA Tx interrupts (to arm ready flag)
|
||||||
void dma1_channel2_isr(){ TXrdy[1] = 1; DMA1->IFCR = DMA_IFCR_CTCIF2; }
|
void dma1_channel2_isr(){ DBG("DMA1 done"); TXrdy[0] = 1; DMA1->IFCR = DMA_IFCR_CTCIF2; }
|
||||||
void dma1_channel4_isr(){ TXrdy[2] = 1; DMA1->IFCR = DMA_IFCR_CTCIF4; }
|
void dma1_channel4_isr(){ DBG("DMA2 done"); TXrdy[1] = 1; DMA1->IFCR = DMA_IFCR_CTCIF4; }
|
||||||
void dma1_channel7_isr(){ TXrdy[0] = 1; DMA1->IFCR = DMA_IFCR_CTCIF7; }
|
void dma1_channel6_isr(){ DBG("DMA3 done"); TXrdy[2] = 1; DMA1->IFCR = DMA_IFCR_CTCIF6; }
|
||||||
void dma2_channel5_isr(){ TXrdy[3] = 1; DMA2->IFCR = DMA_IFCR_CTCIF5; }
|
void dma2_channel5_isr(){ DBG("DMA4 done"); TXrdy[3] = 1; DMA2->IFCR = DMA_IFCR_CTCIF5; }
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "Debug.h"
|
||||||
#include "hardware.h"
|
#include "hardware.h"
|
||||||
#include "ringbuffer.h"
|
#include "ringbuffer.h"
|
||||||
#include "usart.h"
|
#include "usart.h"
|
||||||
@@ -45,7 +46,7 @@ static volatile uint8_t bufovrfl[InterfacesAmount] = {0};
|
|||||||
static uint8_t volatile rcvbuf[InterfacesAmount][USB_RXBUFSZ];
|
static uint8_t volatile rcvbuf[InterfacesAmount][USB_RXBUFSZ];
|
||||||
static uint8_t volatile rcvbuflen[InterfacesAmount] = {0};
|
static uint8_t volatile rcvbuflen[InterfacesAmount] = {0};
|
||||||
// line coding
|
// line coding
|
||||||
#define DEFL {115200, 0, 0, 8}
|
#define DEFL {9600, 0, 0, 8}
|
||||||
usb_LineCoding lineCoding[InterfacesAmount] = {DEFL,DEFL,DEFL,DEFL,DEFL,DEFL,DEFL};
|
usb_LineCoding lineCoding[InterfacesAmount] = {DEFL,DEFL,DEFL,DEFL,DEFL,DEFL,DEFL};
|
||||||
// CDC configured and ready to use
|
// CDC configured and ready to use
|
||||||
volatile uint8_t CDCready[InterfacesAmount] = {0};
|
volatile uint8_t CDCready[InterfacesAmount] = {0};
|
||||||
@@ -117,9 +118,11 @@ static void rxtx_handler(){
|
|||||||
|
|
||||||
// SET_LINE_CODING
|
// SET_LINE_CODING
|
||||||
void linecoding_handler(uint8_t ifno, usb_LineCoding *lc){
|
void linecoding_handler(uint8_t ifno, usb_LineCoding *lc){
|
||||||
|
//DBGch('0' + ifno);
|
||||||
|
//DBG("Linecoding");
|
||||||
lineCoding[ifno] = *lc;
|
lineCoding[ifno] = *lc;
|
||||||
usart_config(ifno, &lineCoding[ifno]); // lc would be real speed!
|
usart_config(ifno, &lineCoding[ifno]); // lc would be real speed!
|
||||||
usart_start(ifno);
|
usart_start(ifno); // restart again with new configuration
|
||||||
}
|
}
|
||||||
|
|
||||||
// clear IN/OUT buffers on connection
|
// clear IN/OUT buffers on connection
|
||||||
@@ -136,10 +139,13 @@ static void clearbufs(uint8_t ifno){
|
|||||||
|
|
||||||
// SET_CONTROL_LINE_STATE
|
// SET_CONTROL_LINE_STATE
|
||||||
void clstate_handler(uint8_t ifno, uint16_t val){
|
void clstate_handler(uint8_t ifno, uint16_t val){
|
||||||
|
//DBGch('0' + ifno);
|
||||||
|
//DBG("CLSTATE");
|
||||||
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){
|
if(val){
|
||||||
clearbufs(ifno);
|
clearbufs(ifno);
|
||||||
|
//usart_config(ifno, &lineCoding[ifno]); // SET_CONTROL_LINE_STATE could be without SET_LINE_CODING
|
||||||
usart_start(ifno);
|
usart_start(ifno);
|
||||||
}else usart_stop(ifno); // turn of USART (if it is @ this interface)
|
}else usart_stop(ifno); // turn of USART (if it is @ this interface)
|
||||||
}
|
}
|
||||||
@@ -147,6 +153,8 @@ void clstate_handler(uint8_t ifno, uint16_t val){
|
|||||||
// 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){
|
||||||
|
//DBGch('0' + ifno);
|
||||||
|
//DBG("BREAK");
|
||||||
CDCready[ifno] = 0;
|
CDCready[ifno] = 0;
|
||||||
usart_stop(ifno); // turn of USART (if it is @ this interface)
|
usart_stop(ifno); // turn of USART (if it is @ this interface)
|
||||||
}
|
}
|
||||||
@@ -176,11 +184,14 @@ void usb_class_request(config_pack_t *req, uint8_t *data, uint16_t datalen){
|
|||||||
case REQ_RECIPIENT_INTERFACE:
|
case REQ_RECIPIENT_INTERFACE:
|
||||||
switch(req->bRequest){
|
switch(req->bRequest){
|
||||||
case SET_LINE_CODING:
|
case SET_LINE_CODING:
|
||||||
|
//DBG("SLC");
|
||||||
if(!data || !datalen) break; // wait for data
|
if(!data || !datalen) break; // wait for data
|
||||||
|
//DBG("test");
|
||||||
if(datalen == sizeof(usb_LineCoding))
|
if(datalen == sizeof(usb_LineCoding))
|
||||||
linecoding_handler(ifno, (usb_LineCoding*)data);
|
linecoding_handler(ifno, (usb_LineCoding*)data);
|
||||||
break;
|
break;
|
||||||
case GET_LINE_CODING:
|
case GET_LINE_CODING:
|
||||||
|
DBG("GLC");
|
||||||
EP_WriteIRQ(0, (uint8_t*)&lineCoding[ifno], sizeof(lineCoding));
|
EP_WriteIRQ(0, (uint8_t*)&lineCoding[ifno], sizeof(lineCoding));
|
||||||
break;
|
break;
|
||||||
case SET_CONTROL_LINE_STATE:
|
case SET_CONTROL_LINE_STATE:
|
||||||
@@ -218,6 +229,7 @@ int USB_sendall(uint8_t ifno){
|
|||||||
// put `buf` into queue to send
|
// put `buf` into queue to send
|
||||||
int USB_send(uint8_t ifno, const uint8_t *buf, int len){
|
int USB_send(uint8_t ifno, const uint8_t *buf, int len){
|
||||||
if(!buf || !CDCready[ifno] || !len) return FALSE;
|
if(!buf || !CDCready[ifno] || !len) return FALSE;
|
||||||
|
if(ifno != ICFG) DBG("USB_send");
|
||||||
uint32_t T0 = Tms;
|
uint32_t T0 = Tms;
|
||||||
while(len){
|
while(len){
|
||||||
if(Tms - T0 > DISCONN_TMOUT){
|
if(Tms - T0 > DISCONN_TMOUT){
|
||||||
@@ -242,7 +254,10 @@ int USB_send(uint8_t ifno, const uint8_t *buf, int len){
|
|||||||
if(lastdsz[ifno] < 0) send_next(ifno);
|
if(lastdsz[ifno] < 0) send_next(ifno);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(buf[len-1] == '\n' && lastdsz[ifno] < 0) send_next(ifno);
|
if(buf[len-1] == '\n' && lastdsz[ifno] < 0){
|
||||||
|
if(ifno != ICFG) DBG("send_next");
|
||||||
|
send_next(ifno);
|
||||||
|
}
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -263,7 +278,10 @@ int USB_putbyte(uint8_t ifno, uint8_t byte){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// send line if got EOL
|
// send line if got EOL
|
||||||
if(byte == '\n' && lastdsz[ifno] < 0) send_next(ifno);
|
if(byte == '\n' && lastdsz[ifno] < 0){
|
||||||
|
if(ifno != ICFG) DBG("send_next");
|
||||||
|
send_next(ifno);
|
||||||
|
}
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,2 +1,2 @@
|
|||||||
#define BUILD_NUMBER "97"
|
#define BUILD_NUMBER "110"
|
||||||
#define BUILD_DATE "2026-02-15"
|
#define BUILD_DATE "2026-02-16"
|
||||||
|
|||||||
Reference in New Issue
Block a user