diff --git a/G4:G431/usart_full_DMA/Makefile b/G4:G431/usart_full_DMA/Makefile new file mode 100644 index 0000000..e92f612 --- /dev/null +++ b/G4:G431/usart_full_DMA/Makefile @@ -0,0 +1,11 @@ +BINARY := blink +PREFIX := /usr/bin/arm-none-eabi +CFLAGS = -std=c23 +# MCU code +MCU := G431xx +# change this linking script depending on particular MCU model, +LDSCRIPT := stm32g431xb.ld + +include ../makefile.g4 +include ../../makefile.stm32 + diff --git a/G4:G431/usart_full_DMA/Readme b/G4:G431/usart_full_DMA/Readme new file mode 100644 index 0000000..6684bc8 --- /dev/null +++ b/G4:G431/usart_full_DMA/Readme @@ -0,0 +1,3 @@ +Simplest example of working with USART1 fully by DMA (both Rx and Tx). +To detect end of line I use interrupt by symbol '\n' in RXD. +Events of pressing/releasing button on PC13 are written onto terminal. diff --git a/G4:G431/usart_full_DMA/blink.bin b/G4:G431/usart_full_DMA/blink.bin new file mode 100755 index 0000000..fd6bd69 Binary files /dev/null and b/G4:G431/usart_full_DMA/blink.bin differ diff --git a/G4:G431/usart_full_DMA/hardware.c b/G4:G431/usart_full_DMA/hardware.c new file mode 100644 index 0000000..2bb9a3b --- /dev/null +++ b/G4:G431/usart_full_DMA/hardware.c @@ -0,0 +1,43 @@ +/* + * This file is part of the usart project. + * Copyright 2026 Edward V. Emelianov . + * + * 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 . + */ + +#include + +#include "hardware.h" + +volatile uint32_t Tms = 0; + +/* Called when systick fires */ +void sys_tick_handler(){ + ++Tms; +} + +void gpio_setup(){ + RCC->AHB2ENR = RCC_AHB2ENR_GPIOAEN | RCC_AHB2ENR_GPIOCEN; // enable PC & PA (USART1) + __DSB(); // Data Synchronization Barrier - wait until data will be really written to AHB2ENR + // set PC6 as push-pull output, PC13 is pulldown input, other as default (AIN) + GPIOC->MODER = (0xffffffff & ~(GPIO_MODER_MODE6 | GPIO_MODER_MODE13)) | MODER_O(6) | MODER_I(13); + GPIOC->PUPDR = PUPD_PD(13); // pulldown + GPIOC->OTYPER = OTYPER_PP(6); // push-pull (default) + // PA9 (Tx) and PA10 (Rx) (don't forget about SWDIO) + GPIOA->MODER = (0xabffffff & ~(GPIO_MODER_MODE9 | GPIO_MODER_MODE10)) | MODER_AF(9) | MODER_AF(10); + GPIOA->AFR[1] = AFRf(7, 9) | AFRf(7, 10); // SWDIO is 0 by default; USART1 is AF7 + // count milliseconds + SysTick_Config(SysFreq / 1000); // arg should be < 0xffffff +} + diff --git a/G4:G431/usart_full_DMA/hardware.h b/G4:G431/usart_full_DMA/hardware.h new file mode 100644 index 0000000..1b01d15 --- /dev/null +++ b/G4:G431/usart_full_DMA/hardware.h @@ -0,0 +1,35 @@ +/* + * This file is part of the usart project. + * Copyright 2026 Edward V. Emelianov . + * + * 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 . + */ + +#pragma once + +// KEY (intpullup->0) - PC13 +// LED - PC6 +#define KEY_PORT GPIOC +#define KEY_PIN (1<<13) +#define LED_PORT GPIOC +#define LED_PIN (1<<6) +#define KEY_PRESSED() (pin_read(KEY_PORT, KEY_PIN) == 1) +#define LED_ON() do{pin_set(LED_PORT, LED_PIN);}while(0) +#define LED_OFF() do{pin_clear(LED_PORT, LED_PIN);}while(0) +#define LED_TOGG() do{pin_toggle(LED_PORT, LED_PIN);}while(0) + + +extern volatile uint32_t Tms; + +void gpio_setup(); diff --git a/G4:G431/usart_full_DMA/main.c b/G4:G431/usart_full_DMA/main.c new file mode 100644 index 0000000..e85bf9f --- /dev/null +++ b/G4:G431/usart_full_DMA/main.c @@ -0,0 +1,66 @@ +/* + * This file is part of the blink project. + * Copyright 2023 Edward V. Emelianov . + * + * 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 . + */ + +#include +#include + +#include "hardware.h" +#include "usart.h" + +// 40ms for debouncing +#define TDEBOUNCE (40) + +int main(void){ + StartHSE(); + gpio_setup(); + usart_setup(115200); + bool pressed = false; + uint32_t Tblink = 0, Tkey = 0; // blink and key pressed time + while(1){ + USART_flags_t f = usart_process(); + if(f.rxovrfl) usart_sendstr("Rx buffer overflow!\n"); + if(f.txerr) usart_sendstr("Tx error!\n"); + if(f.gotstring){ + char *str = usart_getline(); + if(str){ + usart_sendstr("Received:\n"); + usart_sendstr(str); + int l = strlen(str); + if(str[l-1] != '\n'){ + usart_sendstr("\n(only part of line)\n"); + } + } + } + if(Tms - Tblink > 499){ + LED_TOGG(); + Tblink = Tms; + } + if(KEY_PRESSED()){ + if(!pressed){ // new event + pressed = true; + usart_sendstr("Key pressed\n"); + } + Tkey = Tms; + }else{ // key released + if(pressed && (Tms - Tkey) > TDEBOUNCE){ // wait for debounce + pressed = false; + usart_sendstr("Key released\n"); + } + } + } +} diff --git a/G4:G431/usart_full_DMA/openocd.cfg b/G4:G431/usart_full_DMA/openocd.cfg new file mode 100644 index 0000000..22582a6 --- /dev/null +++ b/G4:G431/usart_full_DMA/openocd.cfg @@ -0,0 +1,4 @@ +set FLASH_SIZE 0x20000 + +source [find interface/stlink-v2-1.cfg] +source [find target/stm32g4x.cfg] diff --git a/G4:G431/usart_full_DMA/ringbuffer.c b/G4:G431/usart_full_DMA/ringbuffer.c new file mode 100644 index 0000000..9683f6c --- /dev/null +++ b/G4:G431/usart_full_DMA/ringbuffer.c @@ -0,0 +1,203 @@ +/* + * Copyright 2023 Edward V. Emelianov . + * + * 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 . + */ + +#include +#include +#include "ringbuffer.h" + +#define CHK(b) do{if(!b) return -1;}while(0) + +static int datalen(ringbuffer *b){ + if(b->tail >= b->head) return (b->tail - b->head); + else return (b->length - b->head + b->tail); +} + +// stored data length +int RB_datalen(ringbuffer *b){ + CHK(b); + if(0 == datalen(b)) return 0; // don't block for empty RO operations + if(b->busy) return -1; + b->busy = 1; + int l = datalen(b); + b->busy = 0; + return l; +} + +static int hasbyte(ringbuffer *b, uint8_t byte){ + if(b->head == b->tail) return -1; // no data in buffer + int startidx = b->head; + if(b->head > b->tail){ // + for(int found = b->head; found < b->length; ++found) + if(b->data[found] == byte) return found; + startidx = 0; + } + for(int found = startidx; found < b->tail; ++found) + if(b->data[found] == byte) return found; + return -1; +} + +/** + * @brief RB_hasbyte - check if buffer has given byte stored + * @param b - buffer + * @param byte - byte to find + * @return index if found, -1 if none or busy + */ +int RB_hasbyte(ringbuffer *b, uint8_t byte){ + CHK(b); + if(b->busy) return -1; + b->busy = 1; + int ret = hasbyte(b, byte); + b->busy = 0; + return ret; +} + +// increment head or tail +TRUE_INLINE void incr(ringbuffer *b, volatile int *what, int n){ + *what += n; + if(*what >= b->length) *what -= b->length; +} + +static int read(ringbuffer *b, uint8_t *s, int len){ + int l = datalen(b); + if(!l) return 0; + if(l > len) l = len; + int _1st = b->length - b->head; + if(_1st > l) _1st = l; + if(_1st > len) _1st = len; + memcpy(s, b->data + b->head, _1st); + if(_1st < len && l > _1st){ + memcpy(s+_1st, b->data, l - _1st); + incr(b, &b->head, l); + return l; + } + incr(b, &b->head, _1st); + return _1st; +} + +/** + * @brief RB_read - read data from ringbuffer + * @param b - buffer + * @param s - array to write data + * @param len - max len of `s` + * @return bytes read or -1 if busy + */ +int RB_read(ringbuffer *b, uint8_t *s, int len){ + CHK(b); + if(!s || len < 1) return -1; + if(0 == datalen(b)) return 0; + if(b->busy) return -1; + b->busy = 1; + int r = read(b, s, len); + b->busy = 0; + return r; +} + +// length of data from current position to `byte` (including byte) +static int lento(ringbuffer *b, uint8_t byte){ + int idx = hasbyte(b, byte); + if(idx < 0) return 0; + int partlen = idx + 1 - b->head; + // now calculate length of new data portion + if(idx < b->head) partlen += b->length; + return partlen; +} + +static int readto(ringbuffer *b, uint8_t byte, uint8_t *s, int len){ + int partlen = lento(b, byte); + if(!partlen) return 0; + if(partlen > len) return -1; + return read(b, s, partlen); +} + +/** + * @brief RB_readto fill array `s` with data until byte `byte` (with it) + * @param b - ringbuffer + * @param byte - check byte + * @param s - buffer to write data or NULL to clear data + * @param len - length of `s` or 0 to clear data + * @return amount of bytes written (negative, if lenbusy) return -1; + b->busy = 1; + int n = 0; + if(s && len > 0){ + n = readto(b, byte, s, len); + }else{ + incr(b, &b->head, lento(b, byte)); // just throw data out + } + b->busy = 0; + return n; +} + +int RB_datalento(ringbuffer *b, uint8_t byte){ + CHK(b); + if(0 == datalen(b)) return 0; + if(b->busy) return -1; + b->busy = 1; + int n = lento(b, byte); + b->busy = 0; + return n; +} + +// if l < rest of buffer, truncate and return actually written bytes +static int write(ringbuffer *b, const uint8_t *str, int l){ + int r = b->length - 1 - datalen(b); // rest length + if(r < 1) return 0; + if(l > r) l = r; + int _1st = b->length - b->tail; + if(_1st > l) _1st = l; + memcpy(b->data + b->tail, str, _1st); + if(_1st < l){ // add another piece from start + memcpy(b->data, str+_1st, l-_1st); + } + incr(b, &b->tail, l); + return l; +} + +/** + * @brief RB_write - write some data to ringbuffer + * @param b - buffer + * @param str - data + * @param l - length + * @return amount of bytes written or -1 if busy + */ +int RB_write(ringbuffer *b, const uint8_t *str, int l){ + CHK(b); + if(!str || l < 1) return -1; + if(b->length - datalen(b) < 2) return 0; + if(b->busy) return -1; + b->busy = 1; + int w = write(b, str, l); + b->busy = 0; + return w; +} + +// just delete all information in buffer `b` +int RB_clearbuf(ringbuffer *b){ + CHK(b); + if(b->busy) return -1; + b->busy = 1; + b->head = 0; + b->tail = 0; + memset(b->data, 0, b->length); + b->busy = 0; + return 1; +} diff --git a/G4:G431/usart_full_DMA/ringbuffer.h b/G4:G431/usart_full_DMA/ringbuffer.h new file mode 100644 index 0000000..f9e1e64 --- /dev/null +++ b/G4:G431/usart_full_DMA/ringbuffer.h @@ -0,0 +1,36 @@ +/* + * Copyright 2023 Edward V. Emelianov . + * + * 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 . + */ + +#pragma once + +#include + +typedef struct{ + uint8_t *data; // data buffer + const int length; // its length + int head; // head index + int tail; // tail index + volatile int busy; // == TRUE if buffer is busy now +} ringbuffer; + +int RB_read(ringbuffer *b, uint8_t *s, int len); +int RB_readto(ringbuffer *b, uint8_t byte, uint8_t *s, int len); +int RB_hasbyte(ringbuffer *b, uint8_t byte); +int RB_write(ringbuffer *b, const uint8_t *str, int l); +int RB_datalen(ringbuffer *b); +int RB_datalento(ringbuffer *b, uint8_t byte); +int RB_clearbuf(ringbuffer *b); diff --git a/G4:G431/usart_full_DMA/usart.c b/G4:G431/usart_full_DMA/usart.c new file mode 100644 index 0000000..0c4cbf7 --- /dev/null +++ b/G4:G431/usart_full_DMA/usart.c @@ -0,0 +1,247 @@ +/* + * This file is part of the test project. + * Copyright 2026 Edward V. Emelianov . + * + * 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 . + */ + +#include +#include + +#include "hardware.h" // Tms +#include "ringbuffer.h" +#include "usart.h" + +// USART for text-based protocol, each data portion ends with '\n' +// RX works over circular DMA + +// USART-depending part -------> +// USART1 @ PA9 (Tx) - MUX25 - and PA10 (Rx) - MUX24 +// select USART and its DMA channels +#define USARTx USART1 +#define USARTxAPB APB2ENR +#define USARTxEN RCC_APB2ENR_USART1EN +#define USART_APBEN RCC_APB2 +// DMAMUX channels: 24 - USART1Rx, 25 - USART1Tx +#define DMAMUXRXN (24) +#define DMAMUXTXN (25) +// DMA channels: 1 (0 in MUX) - Rx, 2 (1 in MUX) - Tx; TC and error flags +// use DMA ch2/3 because they both have single IRQ +#define DMAx DMA1 +#define DMAxEN (RCC_AHB1ENR_DMA1EN | RCC_AHB1ENR_DMAMUX1EN) +#define DMACHRX DMA1_Channel1 +#define DMARXTCF DMA_ISR_TCIF1 +#define DMARXEF DMA_ISR_TEIF1 +#define DMACHTX DMA1_Channel2 +#define DMATXTCF DMA_ISR_TCIF2 +#define DMATXEF DMA_ISR_TEIF2 +#define DMAMUXRX DMAMUX1_Channel0 +#define DMAMUXTX DMAMUX1_Channel1 +#define USARTIRQn USART1_IRQn +#define DMARXIRQ DMA1_Channel1_IRQn +#define DMATXIRQ DMA1_Channel2_IRQn + +// interrupt aliases +static void usart_isr(); +static void dmatx_isr(); +static void dmarx_isr(); +void usart1_isr() __attribute__ ((alias ("usart_isr"))); +void dma1_channel1_isr() __attribute__ ((alias ("dmarx_isr"))); +void dma1_channel2_isr() __attribute__ ((alias ("dmatx_isr"))); +// <-------- USART-depending part + +// RX/TX DMA->CCR without EN flag +#define DMARXCCR (DMA_CCR_MINC | DMA_CCR_CIRC | DMA_CCR_TEIE) +#define DMATXCCR (DMA_CCR_MINC | DMA_CCR_DIR | DMA_CCR_TCIE | DMA_CCR_TEIE) + +static volatile bool gotstring = true; // got '\n' in input stream -> force data reading to inbuf +static volatile bool txrdy = true; // Tx DMA not busy +static volatile USART_flags_t curflags; // current flags (cleared in `usart_process`) +// rx/tx DMA buffers +static uint8_t dmarxbuf[USARTRXDMABUFSZ]; +static uint8_t dmatxbuf[USARTTXDMABUFSZ]; +// index of last DMA read position +static uint32_t dma_read_idx = 0; +// for ringbuffer +static uint8_t rbrxbuf[USARTRXBUFSZ], rbtxbuf[USARTTXBUFSZ]; +static ringbuffer TxRB = {.data = rbtxbuf, .length = USARTTXBUFSZ}; +static ringbuffer RxRB = {.data = rbrxbuf, .length = USARTRXBUFSZ}; + +#define USART_BRR(speed) ((SysFreq + (speed)/2) / (speed)) + +static void reinit_rx_dma(){ + dma_read_idx = 0; + RB_clearbuf(&RxRB); + DMACHRX->CCR = DMARXCCR; // stop to reload + DMACHRX->CNDTR = USARTRXDMABUFSZ; + DMACHRX->CMAR = (uint32_t) dmarxbuf; + DMACHRX->CCR = DMARXCCR | DMA_CCR_EN; +} + +void usart_setup(uint32_t speed){ + RCC->AHB1ENR |= DMAxEN; // enable DMA + // enable USART clocking + RCC->USARTxAPB |= USARTxEN; + // baudrate + USARTx->BRR = USART_BRR(speed); + // eol character: '/n' + USARTx->CR2 = USART_CR2_ADD_VAL('\n'); + // enable DMA transmission + USARTx->CR3 = USART_CR3_DMAT | USART_CR3_DMAR; + // set up DMA channels + // Tx channel: mem++, mem->periph, 8bit, compl.&err. irq + DMACHTX->CCR = DMATXCCR; + DMACHTX->CPAR = (uint32_t) &USARTx->TDR; // peripherial address + // Rx channel: mem++, periph->mem, 8bit, compl.&err. irq + DMACHRX->CCR = DMARXCCR; + DMACHRX->CPAR = (uint32_t) &USARTx->RDR; // peripherial address + // set up DMAMUX channels + // enumeration of DMAMUX starts from 0 (DMA - from 1)! + DMAMUXRX->CCR = DMAMUXRXN; + DMAMUXTX->CCR = DMAMUXTXN; + // charmatch interrupt, enable transmitter and receiver, enable usart + USARTx->CR1 = USART_CR1_CMIE | USART_CR1_TE | USART_CR1_RE | USART_CR1_UE; + USARTx->ICR = 0xffffffff; // clear all flags + reinit_rx_dma(); + NVIC_EnableIRQ(USARTIRQn); + NVIC_EnableIRQ(DMARXIRQ); + NVIC_EnableIRQ(DMATXIRQ); +} + +/** + * @brief usart_sendbuf - send next data portion + * @return TRUE if sent something + */ +static bool usart_sendbuf(){ + if(!txrdy) return false; + int rd = RB_read(&TxRB, dmatxbuf, USARTTXDMABUFSZ); + if(rd < 1) return false; // nothing to write or busy + // set up DMA + DMACHTX->CCR = DMATXCCR; + DMACHTX->CMAR = (uint32_t) dmatxbuf; + DMACHTX->CNDTR = rd; + USARTx->ICR = USART_ICR_TCCF; // clear TC flag + txrdy = false; + // activate DMA + DMACHTX->CCR = DMATXCCR | DMA_CCR_EN; + return true; +} + +int usart_send(const char *str, int len){ + if(!str || len < 1) return 0; + uint32_t t = Tms; + int sent = 0; + do{ + IWDG->KR = IWDG_REFRESH; + int put = RB_write(&TxRB, (uint8_t*)str, len); + if(put < 0) continue; // busy + else if(put == 0){ + usart_sendbuf(); // no place + }else{ + len -= put; + sent += put; + str += put; + } + }while(len && (Tms - t) < USARTBLKTMOUT); // not more than `block` ms! + return sent; +} + +int usart_sendstr(const char *str){ + int l = strlen(str); + return usart_send(str, l); +} + +// return current flags +USART_flags_t usart_process(){ + static uint32_t Tlast = 0; + USART_flags_t flags = curflags; + curflags.all = 0; + if(RB_datalento(&TxRB, '\n') > 1 || Tms - Tlast >= USARTSENDTMOUT){ // send buffer as we found '\n' or each 10ms + if(usart_sendbuf()) Tlast = Tms; + } + int remained = DMACHRX->CNDTR; + int write_idx = USARTRXDMABUFSZ - remained; // next symbol to be written + int available = (write_idx - dma_read_idx); // length of data available + if(available < 0) available += USARTRXDMABUFSZ; // write to the left of read + if(available == 0) return flags; + // add next data portion to RX ring buffer + if(available >= (USARTRXDMABUFSZ / 2) || gotstring){ + // copy data in one or two chunks (wrap handling) + bool wrOK = false; + // check if we can write to RB `available` bytes + int rballow = RxRB.length - 1 - RB_datalen(&RxRB); + if(rballow < available){ + if(available > USARTRXDMABUFSZ - 2){ // near overfull + flags.rxovrfl = 1; + reinit_rx_dma(); + RB_clearbuf(&RxRB); + return flags; + } + if(rballow < 1) return flags; + available = rballow; // read at least as we can + } + if(dma_read_idx + available <= USARTRXDMABUFSZ){ // head before tail + if(available == RB_write(&RxRB, &dmarxbuf[dma_read_idx], available)) wrOK = true; + }else{ // head after tail - two chunks + int first = USARTRXDMABUFSZ - dma_read_idx; + if((first == RB_write(&RxRB, &dmarxbuf[dma_read_idx], first)) && + (available - first) == RB_write(&RxRB, dmarxbuf, available - first)) wrOK = true; + } + if(wrOK){ + gotstring = 0; + dma_read_idx = write_idx; // update read pointer + } + } + if(RB_hasbyte(&RxRB, '\n')) flags.gotstring = 1; + return flags; +} + +char *usart_getline(){ + static char buff[256]; + int l = RB_datalento(&RxRB, '\n'); + if(l < 1){ + l = RB_datalen(&RxRB); // Rx ringbuffer could be near overflow but without '\n' + if(l < 255) return NULL; // allow to wait for last symbols + } + if(l > 255){ // overflow -> read at least part of the string + l = 255; + } + if(l != RB_read(&RxRB, (uint8_t*)buff, l)) return NULL; + buff[l] = 0; // return with '\n' at end of line (so user can detect non-finished overflowed lines) + return buff; +} + +// interrupt by '\n' +static void usart_isr(){ + if(USARTx->ISR & USART_ISR_CMF){ // got '\n' @ USARTx + gotstring = true; + } + USARTx->ICR = 0xffffffff; // clear all flags +} + +static void dmarx_isr(){ + volatile uint32_t isr = DMAx->ISR; + if(isr & DMARXEF){ // error + reinit_rx_dma(); + curflags.rxovrfl = 1; + } + DMAx->IFCR = DMARXEF; // clear all flags +} + +static void dmatx_isr(){ + volatile uint32_t isr = DMAx->ISR; + if(isr & DMATXTCF) txrdy = true; + if(isr & DMATXEF) curflags.txerr = 1; + DMAx->IFCR = DMATXTCF | DMATXEF; // clear all flags +} diff --git a/G4:G431/usart_full_DMA/usart.cflags b/G4:G431/usart_full_DMA/usart.cflags new file mode 100644 index 0000000..a07354f --- /dev/null +++ b/G4:G431/usart_full_DMA/usart.cflags @@ -0,0 +1 @@ +-std=c23 \ No newline at end of file diff --git a/G4:G431/usart_full_DMA/usart.config b/G4:G431/usart_full_DMA/usart.config new file mode 100644 index 0000000..c4aadd9 --- /dev/null +++ b/G4:G431/usart_full_DMA/usart.config @@ -0,0 +1,3 @@ +#define EBUG +#define STM32G4 +#define STM32G431xx diff --git a/G4:G431/usart_full_DMA/usart.creator b/G4:G431/usart_full_DMA/usart.creator new file mode 100644 index 0000000..e94cbbd --- /dev/null +++ b/G4:G431/usart_full_DMA/usart.creator @@ -0,0 +1 @@ +[General] diff --git a/G4:G431/usart_full_DMA/usart.cxxflags b/G4:G431/usart_full_DMA/usart.cxxflags new file mode 100644 index 0000000..ea5966d --- /dev/null +++ b/G4:G431/usart_full_DMA/usart.cxxflags @@ -0,0 +1 @@ +-std=c++23 \ No newline at end of file diff --git a/G4:G431/usart_full_DMA/usart.files b/G4:G431/usart_full_DMA/usart.files new file mode 100644 index 0000000..3b1a009 --- /dev/null +++ b/G4:G431/usart_full_DMA/usart.files @@ -0,0 +1,7 @@ +hardware.c +hardware.h +main.c +ringbuffer.c +ringbuffer.h +usart.c +usart.h diff --git a/G4:G431/usart_full_DMA/usart.h b/G4:G431/usart_full_DMA/usart.h new file mode 100644 index 0000000..c65d1fa --- /dev/null +++ b/G4:G431/usart_full_DMA/usart.h @@ -0,0 +1,48 @@ +/* + * This file is part of the test project. + * Copyright 2026 Edward V. Emelianov . + * + * 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 . + */ + +#pragma once + +#include + +// Rx/Tx ring buffer size +#define USARTTXBUFSZ (512) +#define USARTRXBUFSZ (512) +// Rx/Tx DMA buffer size +#define USARTTXDMABUFSZ (256) +#define USARTRXDMABUFSZ (256) + +// blocking timeout - not more than 5ms +#define USARTBLKTMOUT (5) +// send buffer each 10ms +#define USARTSENDTMOUT (10) + +typedef union{ + struct{ + uint8_t txerr : 1; // transmit error + uint8_t rxovrfl : 1; // receive buffer overflow + uint8_t gotstring : 1; // have new string in buffer + }; + uint8_t all; +} USART_flags_t; + +void usart_setup(uint32_t speed); +int usart_send(const char *str, int len); +char *usart_getline(); +int usart_sendstr(const char *str); +USART_flags_t usart_process(); diff --git a/G4:G431/usart_full_DMA/usart.includes b/G4:G431/usart_full_DMA/usart.includes new file mode 100644 index 0000000..641fd56 --- /dev/null +++ b/G4:G431/usart_full_DMA/usart.includes @@ -0,0 +1,4 @@ +. +../inc +../inc/Fx +../inc/cm