mirror of
https://github.com/eddyem/stm32samples.git
synced 2026-03-20 08:40:57 +03:00
USART almost working (but hangs on long messages)
This commit is contained in:
@@ -1,10 +1,10 @@
|
||||
BINARY := usbcangpio
|
||||
# MCU code
|
||||
#MCU := F072xB
|
||||
MCU := F042x6
|
||||
MCU := F072xB
|
||||
#MCU := F042x6
|
||||
# change this linking script depending on particular MCU model,
|
||||
#LDSCRIPT := stm32f072xB.ld
|
||||
LDSCRIPT := stm32f042x6.ld
|
||||
LDSCRIPT := stm32f072x8.ld
|
||||
#LDSCRIPT := stm32f042x6.ld
|
||||
|
||||
DEFINES := -DUSB2_16
|
||||
|
||||
|
||||
@@ -387,8 +387,10 @@ static void CommandParser(char *txt){
|
||||
break;
|
||||
#ifdef STM32F072xB
|
||||
case 'D':
|
||||
USB_sendstr("Go into DFU mode\n");
|
||||
USB_sendall();
|
||||
SEND("Go into DFU mode\n");
|
||||
USB_sendall(ICAN);
|
||||
uint32_t t = Tms;
|
||||
while(Tms - t < 2000){IWDG->KR = IWDG_REFRESH;}
|
||||
Jump2Boot();
|
||||
break;
|
||||
#endif
|
||||
|
||||
@@ -27,13 +27,6 @@
|
||||
static uint16_t monitor_mask[2] = {0}; // pins to monitor == 1 (ONLY GPIO and ADC)
|
||||
static uint16_t oldstates[2][16] = {0}; // previous state (16 bits - as some pins could be analog)
|
||||
|
||||
// strings for keywords
|
||||
const char *str_keywords[] = {
|
||||
#define KW(x) [STR_ ## x] = #x,
|
||||
KEYWORDS
|
||||
#undef KW
|
||||
};
|
||||
|
||||
// intermediate buffer to change pin's settings by user request; after checking in will be copied to the_conf
|
||||
static pinconfig_t pinconfig[2][16] = {0};
|
||||
static uint8_t pinconfig_notinited = 1; // ==0 after first memcpy from the_conf to pinconfig
|
||||
@@ -207,7 +200,8 @@ int chkpinconf(){
|
||||
}
|
||||
// now check USART configuration
|
||||
if(active_usart != -1){
|
||||
if(chkusartconf(&UC)) ret = FALSE;
|
||||
UC.idx = active_usart;
|
||||
if(!chkusartconf(&UC)) ret = FALSE;
|
||||
}else{
|
||||
get_defusartconf(&UC); // clear global configuration
|
||||
the_conf.usartconfig = UC;
|
||||
@@ -318,7 +312,7 @@ int gpio_reinit(){
|
||||
int shift4 = pin << 4;
|
||||
gpio->AFR[0] = (gpio->AFR[0] & ~(0xf << shift4)) | (cfg->afno << shift4);
|
||||
}else{
|
||||
int shift4 = (pin - 8) << 4;
|
||||
int shift4 = (pin - 8) << 2;
|
||||
gpio->AFR[1] = (gpio->AFR[1] & ~(0xf << shift4)) | (cfg->afno << shift4);
|
||||
}
|
||||
if(cfg->monitor && cfg->mode != MODE_AF){
|
||||
|
||||
@@ -99,32 +99,6 @@ typedef struct{
|
||||
} spiconfig_t;
|
||||
*/
|
||||
|
||||
// strings for keywords
|
||||
extern const char *str_keywords[];
|
||||
#define KEYWORDS \
|
||||
KW(AIN) \
|
||||
KW(IN) \
|
||||
KW(OUT) \
|
||||
KW(AF) \
|
||||
KW(PU)\
|
||||
KW(PD) \
|
||||
KW(FL) \
|
||||
KW(PP) \
|
||||
KW(OD) \
|
||||
KW(USART) \
|
||||
KW(SPI) \
|
||||
KW(I2C) \
|
||||
KW(MONITOR) \
|
||||
KW(THRESHOLD) \
|
||||
KW(SPEED) \
|
||||
KW(TEXT)
|
||||
|
||||
enum{ // indexes of string keywords
|
||||
#define KW(k) STR_ ## k,
|
||||
KEYWORDS
|
||||
#undef KW
|
||||
};
|
||||
|
||||
int is_disabled(uint8_t port, uint8_t pin);
|
||||
int chkpinconf();
|
||||
|
||||
|
||||
@@ -25,7 +25,6 @@ extern "C"{
|
||||
#include "adc.h"
|
||||
#include "can.h"
|
||||
#include "flash.h"
|
||||
#include "gpioproto.h"
|
||||
#include "gpio.h"
|
||||
#include "gpioproto.h"
|
||||
#include "usart.h"
|
||||
@@ -36,6 +35,10 @@ extern "C"{
|
||||
|
||||
extern volatile uint32_t Tms;
|
||||
|
||||
static uint8_t curbuf[MAXSTRLEN]; // buffer for receiving data from USART etc
|
||||
|
||||
static uint8_t usart_text = 0; // ==1 for text USART proto
|
||||
|
||||
// TODO: add analog threshold!
|
||||
|
||||
// list of all commands and handlers
|
||||
@@ -56,9 +59,8 @@ extern volatile uint32_t Tms;
|
||||
COMMAND(setiface, "set/get name of interface x (0 - CAN, 1 - GPIO)") \
|
||||
COMMAND(storeconf, "save config to flash") \
|
||||
COMMAND(time, "show current time (ms)") \
|
||||
COMMAND(vdd, "get approx Vdd value (V*100)")
|
||||
|
||||
// COMMAND(USART, "Read USART data or send (USART=hex)")
|
||||
COMMAND(vdd, "get approx Vdd value (V*100)") \
|
||||
COMMAND(USART, "Read USART data or send (USART=hex)")
|
||||
// COMMAND(usartconf, "set USART params (e.g. usartconf=115200 8N1)")
|
||||
// COMMAND(SPI, "Read SPI data or send (SPI=hex)")
|
||||
// COMMAND(spiconf, "set SPI params")
|
||||
@@ -99,7 +101,42 @@ enum MiscValues{
|
||||
MISC_MONITOR = 1,
|
||||
MISC_THRESHOLD,
|
||||
MISC_SPEED,
|
||||
MISC_TEXT
|
||||
MISC_TEXT,
|
||||
MISC_BIN
|
||||
};
|
||||
|
||||
// TODO: add HEX input?
|
||||
|
||||
#define KEYWORDS \
|
||||
KW(AIN) \
|
||||
KW(IN) \
|
||||
KW(OUT) \
|
||||
KW(AF) \
|
||||
KW(PU)\
|
||||
KW(PD) \
|
||||
KW(FL) \
|
||||
KW(PP) \
|
||||
KW(OD) \
|
||||
KW(USART) \
|
||||
KW(SPI) \
|
||||
KW(I2C) \
|
||||
KW(MONITOR) \
|
||||
KW(THRESHOLD) \
|
||||
KW(SPEED) \
|
||||
KW(TEXT) \
|
||||
KW(BIN) \
|
||||
|
||||
enum{ // indexes of string keywords
|
||||
#define KW(k) STR_ ## k,
|
||||
KEYWORDS
|
||||
#undef KW
|
||||
};
|
||||
|
||||
// strings for keywords
|
||||
static const char *str_keywords[] = {
|
||||
#define KW(x) [STR_ ## x] = #x,
|
||||
KEYWORDS
|
||||
#undef KW
|
||||
};
|
||||
|
||||
static const Keyword keywords[] = {
|
||||
@@ -120,17 +157,19 @@ static const Keyword keywords[] = {
|
||||
KEY(THRESHOLD, GROUP_MISC, MISC_THRESHOLD)
|
||||
KEY(SPEED, GROUP_MISC, MISC_SPEED)
|
||||
KEY(TEXT, GROUP_MISC, MISC_TEXT)
|
||||
KEY(BIN, GROUP_MISC, MISC_BIN)
|
||||
#undef K
|
||||
};
|
||||
#define NUM_KEYWORDS (sizeof(keywords)/sizeof(keywords[0]))
|
||||
|
||||
static const char* errtxt[ERR_AMOUNT] = {
|
||||
[ERR_OK] = "OK",
|
||||
[ERR_BADCMD] = "BADCMD",
|
||||
[ERR_BADPAR] = "BADPAR",
|
||||
[ERR_BADVAL] = "BADVAL",
|
||||
[ERR_WRONGLEN] = "WRONGLEN",
|
||||
[ERR_CANTRUN] = "CANTRUN",
|
||||
[ERR_OK] = "OK",
|
||||
[ERR_BADCMD] = "BADCMD",
|
||||
[ERR_BADPAR] = "BADPAR",
|
||||
[ERR_BADVAL] = "BADVAL",
|
||||
[ERR_WRONGLEN] = "WRONGLEN",
|
||||
[ERR_CANTRUN] = "CANTRUN",
|
||||
[ERR_BUSY] = "BUSY",
|
||||
};
|
||||
|
||||
static const char *pinhelp =
|
||||
@@ -141,6 +180,9 @@ static const char *pinhelp =
|
||||
" FUNC: USART or SPI (enable alternate function and configure peripheal)\n"
|
||||
" MISC: MONITOR - send data by USB as only state changed\n"
|
||||
" THRESHOLD (ADC only) - monitoring threshold, ADU\n"
|
||||
" SPEED - interface speed/frequency\n"
|
||||
" TEXT - USART means data as text ('\n'-separated strings)\n"
|
||||
" BIN - USART means data as binary (output: HEX)\n"
|
||||
"\n"
|
||||
;
|
||||
|
||||
@@ -197,7 +239,10 @@ static bool argsvals(char *args, int32_t *parno, int32_t *parval){
|
||||
// `PAx = ` also printed there
|
||||
static void pin_getter(uint8_t port, uint8_t pin){
|
||||
int16_t val = pin_in(port, pin);
|
||||
if(val < 0) SENDn(errtxt[ERR_CANTRUN]);
|
||||
if(val < 0){
|
||||
SENDn(errtxt[ERR_CANTRUN]);
|
||||
return;
|
||||
}
|
||||
SEND(port == 0 ? "PA" : "PB"); SEND(u2str((uint32_t)pin)); SEND(EQ);
|
||||
SENDn(u2str((uint32_t)val));
|
||||
}
|
||||
@@ -284,6 +329,9 @@ static errcodes_t pin_setter(uint8_t port, uint8_t pin, char *setter){
|
||||
case MISC_TEXT: // what to do, if textproto is set, but user wants binary?
|
||||
UsartConf.textproto = 1;
|
||||
break;
|
||||
case MISC_BIN: // clear text flag
|
||||
UsartConf.textproto = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -342,7 +390,13 @@ static errcodes_t cmd_PB(const char *cmd, char *args){
|
||||
}
|
||||
|
||||
static errcodes_t cmd_reinit(const char _U_ *cmd, char _U_ *args){
|
||||
if(gpio_reinit()) return ERR_OK;
|
||||
if(gpio_reinit()){
|
||||
usartconf_t UC;
|
||||
if(get_curusartconf(&UC)){
|
||||
usart_text = UC.textproto;
|
||||
}
|
||||
return ERR_OK;
|
||||
}
|
||||
SEND("Can't reinit: check your configuration!\n");
|
||||
return ERR_AMOUNT;
|
||||
}
|
||||
@@ -573,6 +627,44 @@ static errcodes_t cmd_help(const char _U_ *cmd, char _U_ *args){
|
||||
return ERR_AMOUNT;
|
||||
}
|
||||
|
||||
static int sendfun(const char *s){
|
||||
if(!s) return 0;
|
||||
return USB_sendstr(IGPIO, s);
|
||||
}
|
||||
|
||||
static void sendusartdata(const uint8_t *buf, int len){
|
||||
if(!buf || len < 1) return;
|
||||
SEND(str_keywords[STR_USART]); SEND(EQ);
|
||||
if(usart_text){
|
||||
USB_send(IGPIO, curbuf, len);
|
||||
if(curbuf[len-1] != '\n') NL();
|
||||
}else{
|
||||
NL();
|
||||
hexdump(sendfun, (uint8_t*)curbuf, len);
|
||||
}
|
||||
}
|
||||
|
||||
static errcodes_t cmd_USART(const char _U_ *cmd, char *args){
|
||||
if(!args) return ERR_BADVAL;
|
||||
char *setter = splitargs(args, NULL);
|
||||
if(setter){
|
||||
DBG("Try to send over USART\n");
|
||||
int l = strlen(setter);
|
||||
if(usart_text){ // add '\n' as we removed it @ parser
|
||||
if(setter[l-1] != '\n') setter[l++] = '\n';
|
||||
}
|
||||
l = usart_send((uint8_t*)setter, l);
|
||||
if(l < 0) return ERR_BUSY;
|
||||
else if(l == 0) return ERR_CANTRUN;
|
||||
return ERR_OK;
|
||||
} // getter: try to read
|
||||
int l = usart_receive(curbuf, MAXSTRLEN);
|
||||
if(l < 0) return ERR_CANTRUN;
|
||||
if(l > 0) sendusartdata(curbuf, l);
|
||||
// or silence: nothing to read
|
||||
return ERR_AMOUNT;
|
||||
}
|
||||
|
||||
constexpr uint32_t hash(const char* str, uint32_t h = 0){
|
||||
return *str ? hash(str + 1, h + ((h << 7) ^ *str)) : h;
|
||||
}
|
||||
@@ -599,9 +691,8 @@ static const char *CommandParser(char *str){
|
||||
}
|
||||
|
||||
void GPIO_process(){
|
||||
char inbuff[MAXSTRLEN];
|
||||
int l = RECV(inbuff, MAXSTRLEN);
|
||||
// TODO: check SPI/USART/I2C
|
||||
int l;
|
||||
// TODO: check SPI/I2C etc
|
||||
for(uint8_t port = 0; port < 2; ++port){
|
||||
uint16_t alert = gpio_alert(port);
|
||||
if(alert == 0) continue;
|
||||
@@ -610,11 +701,13 @@ void GPIO_process(){
|
||||
if(alert & pinmask) pin_getter(port, i);
|
||||
}
|
||||
}
|
||||
usart_process(NULL, 0);
|
||||
l = usart_process(curbuf, MAXSTRLEN);
|
||||
if(l > 0) sendusartdata(curbuf, l);
|
||||
l = RECV((char*)curbuf, MAXSTRLEN);
|
||||
if(l == 0) return;
|
||||
if(l < 0) SEND("ERROR: USB buffer overflow or string was too long\n");
|
||||
else{
|
||||
const char *ans = CommandParser(inbuff);
|
||||
const char *ans = CommandParser((char*)curbuf);
|
||||
if(ans) SENDn(ans);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ typedef enum{
|
||||
ERR_BADVAL, // wrong value (for setter)
|
||||
ERR_WRONGLEN, // wrong message length
|
||||
ERR_CANTRUN, // can't run given command due to bad parameters or other
|
||||
ERR_BUSY, // target interface busy, try later
|
||||
ERR_AMOUNT // amount of error codes or "send nothing"
|
||||
} errcodes_t;
|
||||
|
||||
|
||||
@@ -34,9 +34,9 @@ TRUE_INLINE void gpio_setup(){ // setup some common GPIO
|
||||
|
||||
void hardware_setup(){
|
||||
// enable all active GPIO clocking
|
||||
RCC->AHBENR |= RCC_AHBENR_GPIOAEN | RCC_AHBENR_GPIOBEN;
|
||||
RCC->APB1ENR |= RCC_APB2ENR_USART1EN;
|
||||
RCC->APB2ENR |= RCC_APB1ENR_USART2EN;
|
||||
RCC->AHBENR |= RCC_AHBENR_GPIOAEN | RCC_AHBENR_GPIOBEN | RCC_AHBENR_DMA1EN;
|
||||
RCC->APB2ENR |= RCC_APB2ENR_USART1EN | RCC_APB2ENR_SYSCFGEN;
|
||||
RCC->APB1ENR |= RCC_APB1ENR_USART2EN;
|
||||
gpio_setup();
|
||||
//gpio_reinit();
|
||||
adc_setup();
|
||||
|
||||
@@ -32,6 +32,7 @@ void sys_tick_handler(void){
|
||||
int main(void){
|
||||
sysreset();
|
||||
SysTick_Config(6000, 1);
|
||||
StartHSE();
|
||||
flashstorage_init();
|
||||
hardware_setup();
|
||||
USB_setup();
|
||||
|
||||
@@ -32,8 +32,8 @@
|
||||
static uint8_t inbuffer[DMARXBUFSZ]; // DMA in buffer
|
||||
static uint8_t rbbuffer[RXRBSZ]; // for in ringbuffer
|
||||
static uint8_t outbuffer[DMATXBUFSZ]; // DMA out buffer
|
||||
static uint8_t TXrdy = 1; // TX DMA ready
|
||||
static uint8_t RXrdy = 0; // == 1 when got IDLE or '\n' (only when `monitoring` is on
|
||||
static volatile uint8_t TXrdy = 1; // TX DMA ready
|
||||
static volatile uint8_t RXrdy = 0; // == 1 when got IDLE or '\n' (only when `monitoring` is on
|
||||
static uint8_t textformat = 0; // out by '\n'-terminated lines
|
||||
static uint8_t monitor = 0; // monitor USART rx
|
||||
static int dma_read_idx = 0; // start of data in DMA inbuffers
|
||||
@@ -108,18 +108,19 @@ int usart_config(usartconf_t *uc){
|
||||
// Assuming oversampling by 16 (default after reset). For higher baud rates you might use by 8.
|
||||
U->BRR = peripheral_clock / (usartconfig.speed);
|
||||
usartconfig.speed= peripheral_clock / U->BRR; // fix for real speed
|
||||
uint32_t cr1 = 0;
|
||||
// format: 8N1, so CR2 used only for character match (if need)
|
||||
if(usartconfig.monitor){
|
||||
if(usartconfig.textproto){
|
||||
U->CR2 = USART_CR2_ADD_VAL('\n');
|
||||
cr1 |= USART_CR1_CMIE;
|
||||
}else cr1 |= USART_CR1_IDLEIE; // monitor binary data by IDLE flag
|
||||
}
|
||||
uint32_t cr1 = 0, cr3 = 0;
|
||||
textformat = usartconfig.textproto;
|
||||
monitor = usartconfig.monitor;
|
||||
// Enable transmitter, receiver, and interrupts (optional)
|
||||
if(usartconfig.RXen) cr1 |= USART_CR1_RE;
|
||||
if(usartconfig.RXen){
|
||||
cr1 |= USART_CR1_RE;
|
||||
cr3 |= USART_CR3_DMAR;
|
||||
// format: 8N1, so CR2 used only for character match (if need)
|
||||
if(usartconfig.textproto){
|
||||
U->CR2 = USART_CR2_ADD_VAL('\n'); // buffer text data by EOL
|
||||
cr1 |= USART_CR1_CMIE;
|
||||
}else cr1 |= USART_CR1_IDLEIE; // buffer binary data by IDLE flag
|
||||
}
|
||||
if(usartconfig.TXen){
|
||||
cr1 |= USART_CR1_TE;
|
||||
// DMA Tx
|
||||
@@ -127,9 +128,11 @@ int usart_config(usartconf_t *uc){
|
||||
T->CCR = 0;
|
||||
T->CPAR = (uint32_t) &U->TDR;
|
||||
T->CCR = DMA_CCR_MINC | DMA_CCR_DIR | DMA_CCR_TCIE;
|
||||
cr3 |= USART_CR3_DMAT;
|
||||
}
|
||||
// Main config
|
||||
U->CR1 = cr1;
|
||||
U->CR3 = cr3;
|
||||
curUSARTidx = No;
|
||||
// all OK -> copy to global config
|
||||
the_conf.usartconfig = usartconfig;
|
||||
@@ -140,26 +143,21 @@ int usart_config(usartconf_t *uc){
|
||||
int usart_start(){
|
||||
if(curUSARTidx == -1) return FALSE;
|
||||
volatile USART_TypeDef *U = Usarts[curUSARTidx];
|
||||
if(monitor) NVIC_EnableIRQ(UIRQs[curUSARTidx]);
|
||||
NVIC_EnableIRQ(UIRQs[curUSARTidx]); // copy to ring buffer after each '\n' in text mode or IDLE in binary
|
||||
NVIC_EnableIRQ(DMA1_Channel4_5_IRQn);
|
||||
// reset Rx DMA
|
||||
if(U->CR1 & USART_CR1_RE){
|
||||
volatile DMA_Channel_TypeDef *R = DMA1_Channel5;
|
||||
dma_read_idx = 0;
|
||||
R->CCR = 0;
|
||||
R->CPAR = (uint32_t) U->RDR;
|
||||
RB_clearbuf(&RBin);
|
||||
R->CPAR = (uint32_t) &U->RDR;
|
||||
R->CMAR = (uint32_t) inbuffer;
|
||||
R->CNDTR = DMARXBUFSZ;
|
||||
R->CCR = DMA_CCR_MINC | DMA_CCR_CIRC | DMA_CCR_EN;
|
||||
RB_clearbuf(&RBin);
|
||||
}
|
||||
U->CR1 |= USART_CR1_UE; // enable USARTx
|
||||
U->ICR = 0xFFFFFFFF; // Clear flags
|
||||
// Wait for the idle frame to complete (optional)
|
||||
uint32_t tmout = 16000000;
|
||||
while(!(U->ISR & USART_ISR_TC)){
|
||||
if (--tmout == 0) break;
|
||||
}
|
||||
TXrdy = 1;
|
||||
return TRUE;
|
||||
}
|
||||
@@ -208,33 +206,36 @@ int usart_process(uint8_t *buf, int len){
|
||||
if(curUSARTidx == -1 || !(Usarts[curUSARTidx]->CR1 & USART_CR1_UE)) return -1; // none activated or started
|
||||
int ret = 0; // returned value
|
||||
// Input data
|
||||
int write_idx = DMARXBUFSZ - DMA1_Channel5->CNDTR; // next symbol to be written
|
||||
int remained = DMA1_Channel5->CNDTR;
|
||||
int write_idx = DMARXBUFSZ - remained; // next symbol to be written
|
||||
int available = (write_idx - dma_read_idx); // length of data available
|
||||
int monitored_len = available;
|
||||
uint8_t locmonitor = monitor; // if `buf` not pointed, set this flag to zero
|
||||
if(available < 0) available += DMARXBUFSZ; // write to the left of read
|
||||
if(available){
|
||||
if(RXrdy){
|
||||
if(locmonitor){
|
||||
if(buf && len > 0){
|
||||
if(len < available) available = len;
|
||||
}else RXrdy = 0;
|
||||
if(len < monitored_len) monitored_len = len;
|
||||
}else locmonitor = 0;
|
||||
}
|
||||
// TODO: force copying data to "async" buffer in case of overflow danger
|
||||
if(available >= (DMARXBUFSZ/2) || RXrdy){ // enough data or lonely couple of bytes but need to show
|
||||
// copy data in one or two chunks (wrap handling)
|
||||
int wrOK = FALSE;
|
||||
if(dma_read_idx + available <= DMARXBUFSZ){ // head before tail
|
||||
if(RXrdy){
|
||||
memcpy(buf, &inbuffer[dma_read_idx], available);
|
||||
ret = available;
|
||||
if(locmonitor){
|
||||
memcpy(buf, &inbuffer[dma_read_idx], monitored_len);
|
||||
ret = monitored_len;
|
||||
wrOK = TRUE;
|
||||
}else{
|
||||
if(available == RB_write(&RBin, &inbuffer[dma_read_idx], available)) wrOK = TRUE;
|
||||
}
|
||||
}else{ // head after tail - two chunks
|
||||
int first = DMARXBUFSZ - dma_read_idx;
|
||||
if(RXrdy){
|
||||
if(locmonitor){
|
||||
memcpy(buf, &inbuffer[dma_read_idx], first);
|
||||
memcpy(buf, inbuffer, available - first);
|
||||
ret = available;
|
||||
memcpy(buf, inbuffer, monitored_len - first);
|
||||
ret = monitored_len;
|
||||
wrOK = TRUE;
|
||||
}else{
|
||||
if((first == RB_write(&RBin, &inbuffer[dma_read_idx], first)) &&
|
||||
@@ -297,9 +298,9 @@ static void usart_isr(){
|
||||
}
|
||||
|
||||
void dma1_channel4_5_isr(){ // TX ready, channel5
|
||||
if(DMA1->ISR & DMA_ISR_TCIF5){
|
||||
if(DMA1->ISR & DMA_ISR_TCIF4){
|
||||
TXrdy = 1;
|
||||
DMA1->IFCR = DMA_IFCR_CTCIF5;
|
||||
DMA1->IFCR = DMA_IFCR_CTCIF4;
|
||||
DMA1_Channel4->CCR &= ~DMA_CCR_EN; // disable DMA channel until next send
|
||||
}
|
||||
}
|
||||
|
||||
Binary file not shown.
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE QtCreatorProject>
|
||||
<!-- Written by QtCreator 18.0.2, 2026-03-13T00:12:36. -->
|
||||
<!-- Written by QtCreator 18.0.2, 2026-03-14T01:13:52. -->
|
||||
<qtcreator>
|
||||
<data>
|
||||
<variable>EnvironmentId</variable>
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
#define BUILD_NUMBER "156"
|
||||
#define BUILD_DATE "2026-03-12"
|
||||
#define BUILD_NUMBER "173"
|
||||
#define BUILD_DATE "2026-03-14"
|
||||
|
||||
Reference in New Issue
Block a user