This commit is contained in:
Edward Emelianov
2026-07-16 20:37:33 +03:00
parent cdef16cad1
commit f2a444c90e
17 changed files with 713 additions and 0 deletions

View File

@@ -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

View File

@@ -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.

BIN
G4:G431/usart_full_DMA/blink.bin Executable file

Binary file not shown.

View File

@@ -0,0 +1,43 @@
/*
* This file is part of the usart 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/>.
*/
#include <stm32g4.h>
#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
}

View File

@@ -0,0 +1,35 @@
/*
* This file is part of the usart 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
// 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();

View File

@@ -0,0 +1,66 @@
/*
* This file is part of the blink project.
* Copyright 2023 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/>.
*/
#include <stm32g4.h>
#include <string.h>
#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");
}
}
}
}

View File

@@ -0,0 +1,4 @@
set FLASH_SIZE 0x20000
source [find interface/stlink-v2-1.cfg]
source [find target/stm32g4x.cfg]

View File

@@ -0,0 +1,203 @@
/*
* Copyright 2023 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/>.
*/
#include <string.h>
#include <stm32g4.h>
#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 len<data in buffer or buffer is busy)
*/
int RB_readto(ringbuffer *b, uint8_t byte, 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 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;
}

View File

@@ -0,0 +1,36 @@
/*
* Copyright 2023 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 <stdint.h>
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);

View File

@@ -0,0 +1,247 @@
/*
* This file is part of the test 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/>.
*/
#include <stm32g4.h>
#include <string.h>
#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
}

View File

@@ -0,0 +1 @@
-std=c23

View File

@@ -0,0 +1,3 @@
#define EBUG
#define STM32G4
#define STM32G431xx

View File

@@ -0,0 +1 @@
[General]

View File

@@ -0,0 +1 @@
-std=c++23

View File

@@ -0,0 +1,7 @@
hardware.c
hardware.h
main.c
ringbuffer.c
ringbuffer.h
usart.c
usart.h

View File

@@ -0,0 +1,48 @@
/*
* This file is part of the test 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 <stdint.h>
// 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();

View File

@@ -0,0 +1,4 @@
.
../inc
../inc/Fx
../inc/cm