mirror of
https://github.com/eddyem/stm32samples.git
synced 2026-03-20 00:30:57 +03:00
USART1 @ STM32G0B1
This commit is contained in:
Binary file not shown.
@@ -32,6 +32,7 @@ void sys_tick_handler(void){
|
|||||||
* Set up timer to fire every x milliseconds
|
* Set up timer to fire every x milliseconds
|
||||||
*/
|
*/
|
||||||
static void systick_setup(uint32_t xms){ // xms < 2098!!!
|
static void systick_setup(uint32_t xms){ // xms < 2098!!!
|
||||||
|
blink_ctr = 0;
|
||||||
static uint32_t curms = 0;
|
static uint32_t curms = 0;
|
||||||
if(curms == xms) return;
|
if(curms == xms) return;
|
||||||
// 8MHz - HCLK/8
|
// 8MHz - HCLK/8
|
||||||
@@ -65,6 +66,7 @@ int main(void){
|
|||||||
if(M & 1) pin_set(GPIOC, 1<<8);
|
if(M & 1) pin_set(GPIOC, 1<<8);
|
||||||
else pin_clear(GPIOC, 1<<8);
|
else pin_clear(GPIOC, 1<<8);
|
||||||
if(++M == 18) M = 0;
|
if(++M == 18) M = 0;
|
||||||
|
while(blink_ctr == 0);
|
||||||
}else{ // key pressed - blink with period of 1s
|
}else{ // key pressed - blink with period of 1s
|
||||||
if(pressed){
|
if(pressed){
|
||||||
M = 0;
|
M = 0;
|
||||||
|
|||||||
30
G0:G070,G0B1/g0b1/hardware.c
Normal file
30
G0:G070,G0B1/g0b1/hardware.c
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
/*
|
||||||
|
* 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 "hardware.h"
|
||||||
|
|
||||||
|
void gpio_setup(){
|
||||||
|
RCC->IOPENR = RCC_IOPENR_GPIOCEN | RCC_IOPENR_GPIOBEN;
|
||||||
|
// set PC8 as opendrain output, PC0 is pullup input, other as default (AIN)
|
||||||
|
GPIOC->MODER = (0xffffffff & ~(GPIO_MODER_MODE6 | GPIO_MODER_MODE13)) | GPIO_MODER_MODER6_O; // GPIO_MODER_MODER13_I == 0
|
||||||
|
GPIOC->PUPDR = GPIO_PUPDR13_PD; // pull down
|
||||||
|
// USART1: PB6 - Tx (AF0), PB7 - Rx (AF0)
|
||||||
|
GPIOB->MODER = MODER_AF(6) | MODER_AF(7);
|
||||||
|
GPIOB->AFR[0] = 0;
|
||||||
|
// RCC->CCIPR = 0; // default -> sysclk/pclk source
|
||||||
|
}
|
||||||
35
G0:G070,G0B1/g0b1/hardware.h
Normal file
35
G0:G070,G0B1/g0b1/hardware.h
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
/*
|
||||||
|
* 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 "stm32g0.h"
|
||||||
|
|
||||||
|
// 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_TOGGLE() do{pin_toggle(LED_PORT, LED_PIN);}while(0)
|
||||||
|
|
||||||
|
extern volatile uint32_t Tms;
|
||||||
|
void gpio_setup();
|
||||||
@@ -17,70 +17,50 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "stm32g0.h"
|
#include "stm32g0.h"
|
||||||
|
#include "hardware.h"
|
||||||
|
#include "usart.h"
|
||||||
|
|
||||||
#define KEY_PORT GPIOC
|
volatile uint32_t Tms = 0; // milliseconds
|
||||||
#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)
|
|
||||||
|
|
||||||
// KEY (intpullup->0) - PC13
|
|
||||||
// LED - PC6
|
|
||||||
|
|
||||||
static volatile uint32_t blink_ctr = 0;
|
|
||||||
|
|
||||||
/* Called when systick fires */
|
/* Called when systick fires */
|
||||||
void sys_tick_handler(void){
|
void sys_tick_handler(void){
|
||||||
++blink_ctr;
|
++Tms;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Set up timer to fire every x milliseconds
|
* Set up timer to fire every x milliseconds
|
||||||
*/
|
*/
|
||||||
static void systick_setup(uint32_t xms){ // xms < 2098!!!
|
static void systick_setup(uint32_t xms){ // xms < 2098!!!
|
||||||
blink_ctr = 0;
|
Tms = 0;
|
||||||
static uint32_t curms = 0;
|
static uint32_t curms = 0;
|
||||||
if(curms == xms) return;
|
if(curms == xms) return;
|
||||||
// 8MHz - HCLK/8
|
|
||||||
// this function also clears counter so it starts right away
|
// this function also clears counter so it starts right away
|
||||||
SysTick_Config(8000 * xms); // arg should be < 0xffffff, so ms should be < 2098
|
SysTick_Config(SysFreq / 8000 * xms); // arg should be < 0xffffff, so ms should be < 2098
|
||||||
curms = xms;
|
curms = xms;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void gpio_setup(void){
|
|
||||||
RCC->IOPENR = RCC_IOPENR_GPIOCEN; // enable PC
|
|
||||||
// set PC8 as opendrain output, PC0 is pullup input, other as default (AIN)
|
|
||||||
GPIOC->MODER = (0xffffffff & ~(GPIO_MODER_MODE6 | GPIO_MODER_MODE13)) | GPIO_MODER_MODER6_O; // GPIO_MODER_MODER13_I == 0
|
|
||||||
GPIOC->PUPDR = GPIO_PUPDR13_PD; // pull down
|
|
||||||
}
|
|
||||||
|
|
||||||
static const uint32_t L[] = {125,100,125,100,125,200, 350,100,350,100,350,200, 125,100,125,100,125, 1000};
|
|
||||||
|
|
||||||
int main(void){
|
int main(void){
|
||||||
StartHSE();
|
StartHSE();
|
||||||
gpio_setup();
|
gpio_setup();
|
||||||
systick_setup(500);
|
systick_setup(1); // run each 1ms
|
||||||
|
usart_setup(115200);
|
||||||
uint32_t M = 0;
|
uint32_t M = 0;
|
||||||
int pressed = 0;
|
//int pressed = 0;
|
||||||
/* Do nothing in main loop */
|
/* Do nothing in main loop */
|
||||||
while (1){
|
while(1){
|
||||||
if(KEY_PRESSED()){ // key pressed - 'sos'
|
if(Tms - M > 499){
|
||||||
pressed = 1;
|
LED_TOGGLE();
|
||||||
systick_setup(L[M]);
|
M = Tms;
|
||||||
if(M & 1) LED_OFF();
|
}
|
||||||
else LED_ON();
|
//if(KEY_PRESSED()){ // key pressed - 'sos'
|
||||||
if(++M == 18) M = 0;
|
USART_flags_t f = usart_process();
|
||||||
while(blink_ctr == 0);
|
if(f.rxovrfl) usart_sendstr("Rx overflow!\n");
|
||||||
}else{ // key not pressed - blink with period of 1s
|
if(f.txerr) usart_sendstr("Tx error!\n");
|
||||||
if(pressed){
|
char *got = usart_getline();
|
||||||
M = 0;
|
if(got){
|
||||||
pressed = 0;
|
usart_sendstr("You sent:\n");
|
||||||
systick_setup(500);
|
usart_sendstr(got);
|
||||||
}
|
usart_sendstr("\n=======================\n");
|
||||||
if(blink_ctr & 1) LED_ON();
|
|
||||||
else LED_OFF();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
180
G0:G070,G0B1/g0b1/ringbuffer.c
Normal file
180
G0:G070,G0B1/g0b1/ringbuffer.c
Normal file
@@ -0,0 +1,180 @@
|
|||||||
|
/*
|
||||||
|
* 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 <stm32g0.h>
|
||||||
|
#include "ringbuffer.h"
|
||||||
|
|
||||||
|
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){
|
||||||
|
if(!b || 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 || 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){
|
||||||
|
if(!b || 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){
|
||||||
|
if(!b || b->busy || !s || len < 1) 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
|
||||||
|
* @param len - length of `s`
|
||||||
|
* @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){
|
||||||
|
if(!b || b->busy || !s || len < 1) return -1;
|
||||||
|
b->busy = 1;
|
||||||
|
int n = readto(b, byte, s, len);
|
||||||
|
b->busy = 0;
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
int RB_datalento(ringbuffer *b, uint8_t byte){
|
||||||
|
if(!b || 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){
|
||||||
|
if(!b || b->busy || !str || l < 1) 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){
|
||||||
|
if(!b || b->busy) return -1;
|
||||||
|
b->busy = 1;
|
||||||
|
b->head = 0;
|
||||||
|
b->tail = 0;
|
||||||
|
b->busy = 0;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
36
G0:G070,G0B1/g0b1/ringbuffer.h
Normal file
36
G0:G070,G0B1/g0b1/ringbuffer.h
Normal 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);
|
||||||
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-03-01T23:07:02. -->
|
<!-- Written by QtCreator 18.0.2, 2026-03-02T23:12:42. -->
|
||||||
<qtcreator>
|
<qtcreator>
|
||||||
<data>
|
<data>
|
||||||
<variable>EnvironmentId</variable>
|
<variable>EnvironmentId</variable>
|
||||||
|
|||||||
@@ -1,2 +1,8 @@
|
|||||||
|
hardware.c
|
||||||
|
hardware.h
|
||||||
main.c
|
main.c
|
||||||
|
ringbuffer.c
|
||||||
|
ringbuffer.h
|
||||||
systick_blink.c
|
systick_blink.c
|
||||||
|
usart.c
|
||||||
|
usart.h
|
||||||
|
|||||||
194
G0:G070,G0B1/g0b1/usart.c
Normal file
194
G0:G070,G0B1/g0b1/usart.c
Normal file
@@ -0,0 +1,194 @@
|
|||||||
|
/*
|
||||||
|
* 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 <stm32g0.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "hardware.h" // Tms
|
||||||
|
#include "ringbuffer.h"
|
||||||
|
#include "usart.h"
|
||||||
|
|
||||||
|
// We do not use a ring buffer here because we expect incoming information
|
||||||
|
// to flow slowly from the terminal.
|
||||||
|
|
||||||
|
// USART-depending part ------->
|
||||||
|
// select USART and its DMA channels
|
||||||
|
#define USARTx USART1
|
||||||
|
#define USARTxAPB APBENR2
|
||||||
|
#define USARTxEN RCC_APBENR2_USART1EN
|
||||||
|
#define USART_APBEN RCC_APB1
|
||||||
|
// DMAMUX channels: 50 - USART1Rx, 51 - USART1Tx
|
||||||
|
#define DMAMUXRXN (50)
|
||||||
|
#define DMAMUXTXN (51)
|
||||||
|
// DMA channels: 2 (1 in MUX) - Rx, 3 (2 in MUX) - Tx; TC and error flags
|
||||||
|
// use DMA ch2/3 because they both have single IRQ
|
||||||
|
#define DMAx DMA1
|
||||||
|
#define DMAxEN RCC_AHBENR_DMA1EN
|
||||||
|
#define DMACHRX DMA1_Channel2
|
||||||
|
#define DMARXTCF DMA_ISR_TCIF2
|
||||||
|
#define DMARXEF DMA_ISR_TEIF2
|
||||||
|
#define DMACHTX DMA1_Channel3
|
||||||
|
#define DMATXTCF DMA_ISR_TCIF3
|
||||||
|
#define DMATXEF DMA_ISR_TEIF3
|
||||||
|
#define DMAMUXRX DMAMUX1_Channel1
|
||||||
|
#define DMAMUXTX DMAMUX1_Channel2
|
||||||
|
#define USARTIRQn USART1_IRQn
|
||||||
|
#define DMAIRQ DMA1_Channel2_3_IRQn
|
||||||
|
// interrupt aliases
|
||||||
|
static void usart_isr();
|
||||||
|
static void dma_isr();
|
||||||
|
void usart1_isr() __attribute__ ((alias ("usart_isr")));
|
||||||
|
void dma1_channel2_3_isr() __attribute__ ((alias ("dma_isr")));
|
||||||
|
// <-------- USART-depending part
|
||||||
|
|
||||||
|
// RX/TX DMA->CCR without EN flag
|
||||||
|
#define DMARXCCR (DMA_CCR_MINC | DMA_CCR_TCIE | DMA_CCR_TEIE)
|
||||||
|
#define DMATXCCR (DMA_CCR_MINC | DMA_CCR_DIR | DMA_CCR_TCIE | DMA_CCR_TEIE)
|
||||||
|
|
||||||
|
static volatile uint8_t txrdy = 1, rxrdy = 0; // transmission done, next line received
|
||||||
|
static volatile USART_flags_t curflags; // current flags (cleared in `usart_process`)
|
||||||
|
static volatile uint8_t rbufno = 0; // current buf number
|
||||||
|
static uint8_t rbuf[USARTRXBUFSZ][2];
|
||||||
|
static uint8_t txbuf[USARTTXBUFSZ]; // for ringbuffer
|
||||||
|
static ringbuffer TxRB = {.data = txbuf, .length = USARTTXBUFSZ};
|
||||||
|
|
||||||
|
char *usart_getline(){
|
||||||
|
if(!rxrdy) return NULL;
|
||||||
|
rxrdy = 0; // clear ready flag
|
||||||
|
return (char*)rbuf[!rbufno]; // current buffer is in filling stage, return old - filled - buffer
|
||||||
|
}
|
||||||
|
|
||||||
|
#define USART_BRR(speed) ((SysFreq + speed/2) / speed)
|
||||||
|
|
||||||
|
void usart_setup(uint32_t speed){
|
||||||
|
RCC->AHBENR |= 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
|
||||||
|
DMACHRX->CNDTR = USARTRXBUFSZ;
|
||||||
|
DMACHRX->CMAR = (uint32_t)&rbuf[rbufno];
|
||||||
|
// 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
|
||||||
|
DMACHRX->CCR = DMARXCCR | DMA_CCR_EN; // start receiving right now
|
||||||
|
NVIC_EnableIRQ(USARTIRQn);
|
||||||
|
NVIC_EnableIRQ(DMAIRQ);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief usart_sendbuf - send next data portion
|
||||||
|
* @return TRUE if sent something
|
||||||
|
*/
|
||||||
|
static int usart_sendbuf(){
|
||||||
|
static uint8_t dmatxbuf[USARTTXDMABUFSZ];
|
||||||
|
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 = 0;
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
return flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
// interrupt by '\n'
|
||||||
|
static void usart_isr(){
|
||||||
|
if(USARTx->ISR & USART_ISR_CMF){ // got '\n' @ USARTx
|
||||||
|
DMACHRX->CCR = DMARXCCR;
|
||||||
|
rxrdy = 1;
|
||||||
|
int l = USARTRXBUFSZ - DMACHRX->CNDTR - 1; // strlen without '\n'
|
||||||
|
rbuf[rbufno][l] = 0; // throw out '\n'
|
||||||
|
rbufno = !rbufno; // prepare next buffer to receive
|
||||||
|
// reload DMA Rx with next buffer
|
||||||
|
DMACHRX->CMAR = (uint32_t) rbuf[rbufno];
|
||||||
|
DMACHRX->CNDTR = USARTRXBUFSZ;
|
||||||
|
DMACHRX->CCR = DMARXCCR | DMA_CCR_EN;
|
||||||
|
}
|
||||||
|
USARTx->ICR = 0xffffffff; // clear all flags
|
||||||
|
}
|
||||||
|
|
||||||
|
// ch2 - Tx, ch3 - Rx
|
||||||
|
static void dma_isr(){
|
||||||
|
volatile uint32_t isr = DMAx->ISR;
|
||||||
|
if(isr & DMATXTCF) txrdy = 1;
|
||||||
|
if(isr & DMATXEF) curflags.txerr = 1;
|
||||||
|
if(isr & (DMARXTCF | DMARXEF)){ // receive complete or error -> buffer overflow
|
||||||
|
if(rbuf[rbufno][USARTRXBUFSZ-1] != '\n'){ // last symbol is not a newline
|
||||||
|
curflags.rxovrfl = 1;
|
||||||
|
DMACHRX->CCR = DMARXCCR; // stop to reload
|
||||||
|
DMACHRX->CNDTR = USARTRXBUFSZ;
|
||||||
|
DMACHRX->CMAR = (uint32_t) rbuf[rbufno];
|
||||||
|
DMACHRX->CCR = DMARXCCR | DMA_CCR_EN;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DMAx->IFCR = 0xffffffff; // clear all flags
|
||||||
|
}
|
||||||
42
G0:G070,G0B1/g0b1/usart.h
Normal file
42
G0:G070,G0B1/g0b1/usart.h
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
/*
|
||||||
|
* 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
|
||||||
|
|
||||||
|
#define USARTTXBUFSZ (1024)
|
||||||
|
#define USARTRXBUFSZ (128)
|
||||||
|
#define USARTTXDMABUFSZ (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 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();
|
||||||
@@ -80,12 +80,17 @@ TRUE_INLINE void StartHSEHSI(int isHSE){
|
|||||||
WAITWHILE(PWR->SR2 & PWR_SR2_VOSF);
|
WAITWHILE(PWR->SR2 & PWR_SR2_VOSF);
|
||||||
if(isHSE){
|
if(isHSE){
|
||||||
RCC->PLLCFGR = ((PLLR-1)<<29) | ((PLLQ-1)<<25) | ((PLLP-1)<<17) | (PLLN<<8) | ((PLLM-1)<<4)
|
RCC->PLLCFGR = ((PLLR-1)<<29) | ((PLLQ-1)<<25) | ((PLLP-1)<<17) | (PLLN<<8) | ((PLLM-1)<<4)
|
||||||
| RCC_PLLCFGR_PLLREN | RCC_PLLCFGR_PLLQEN /* | RCC_PLLCFGR_PLLPEN */
|
| RCC_PLLCFGR_PLLREN | RCC_PLLCFGR_PLLPEN
|
||||||
|
#ifdef STM32G0B1xx
|
||||||
|
| RCC_PLLCFGR_PLLQEN
|
||||||
|
#endif
|
||||||
| RCC_PLLCFGR_PLLSRC_HSE;
|
| RCC_PLLCFGR_PLLSRC_HSE;
|
||||||
}else{ // 64MHz from HSI16
|
}else{ // 64MHz from HSI16
|
||||||
RCC->PLLCFGR = (8<<8) | (1<<4)
|
RCC->PLLCFGR = ((PLLR-1)<<29) | ((PLLQ-1)<<25) | ((PLLP-1)<<17) | (8<<8) | (1<<4)
|
||||||
// enable P if need
|
| RCC_PLLCFGR_PLLREN | RCC_PLLCFGR_PLLPEN
|
||||||
| RCC_PLLCFGR_PLLREN | RCC_PLLCFGR_PLLQEN /* | RCC_PLLCFGR_PLLPEN */
|
#ifdef STM32G0B1xx
|
||||||
|
| RCC_PLLCFGR_PLLQEN
|
||||||
|
#endif
|
||||||
| RCC_PLLCFGR_PLLSRC_HSI;
|
| RCC_PLLCFGR_PLLSRC_HSI;
|
||||||
}
|
}
|
||||||
RCC->CR |= RCC_CR_PLLON;
|
RCC->CR |= RCC_CR_PLLON;
|
||||||
@@ -93,6 +98,7 @@ TRUE_INLINE void StartHSEHSI(int isHSE){
|
|||||||
FLASH->ACR |= FLASH_ACR_PRFTEN | FLASH_ACR_ICEN | FLASH_ACR_LATENCY_2; // FLASH_ACR_LATENCY_2 for 64MHz
|
FLASH->ACR |= FLASH_ACR_PRFTEN | FLASH_ACR_ICEN | FLASH_ACR_LATENCY_2; // FLASH_ACR_LATENCY_2 for 64MHz
|
||||||
// set sysclk switch to pll, setup AHB/APB
|
// set sysclk switch to pll, setup AHB/APB
|
||||||
RCC->CFGR = RCC_CFGR_SW_1 | PPRE << 12 | HPRE << 8;
|
RCC->CFGR = RCC_CFGR_SW_1 | PPRE << 12 | HPRE << 8;
|
||||||
|
SysFreq = 64000000;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define StartHSE() do{StartHSEHSI(1);}while(0)
|
#define StartHSE() do{StartHSEHSI(1);}while(0)
|
||||||
@@ -224,6 +230,33 @@ TRUE_INLINE void StartHSEHSI(int isHSE){
|
|||||||
#define GPIO_OSPEEDR15_MED ((uint32_t)(1<<30))
|
#define GPIO_OSPEEDR15_MED ((uint32_t)(1<<30))
|
||||||
#define GPIO_OSPEEDR15_HIGH ((uint32_t)(3<<30))
|
#define GPIO_OSPEEDR15_HIGH ((uint32_t)(3<<30))
|
||||||
|
|
||||||
|
// clear MODER: ~GPIO_MODER_MODERXX_Msk, you should AND these
|
||||||
|
#define MODER_CLR(n) (~(3<<(n*2)))
|
||||||
|
// _AI - analog inpt, _O - general output, _AF - alternate function
|
||||||
|
// these should be OR'ed
|
||||||
|
#define MODER_I(n) (0)
|
||||||
|
#define MODER_O(n) (1<<(n*2))
|
||||||
|
#define MODER_AF(n) (2<<(n*2))
|
||||||
|
#define MODER_AI(n) (3<<(n*2))
|
||||||
|
// OSPEED: low, medium, high
|
||||||
|
#define OSPEED_CLR(n) (~(3<<(n*2)))
|
||||||
|
#define OSPEED_VLO(n) (0)
|
||||||
|
#define OSPEED_LO(n) (1<<(n*2))
|
||||||
|
#define OSPEED_MED(n) (2<<(n*2))
|
||||||
|
#define OSPEED_HI(n) (3<<(n*2))
|
||||||
|
// PUPD: pull up/down
|
||||||
|
#define PUPD_CLR(n) (~(3<<(n*2)))
|
||||||
|
#define PUPD_PU(n) (1<<(n*2))
|
||||||
|
#define PUPD_PD(n) (2<<(n*2))
|
||||||
|
// OTYPER: bit==1 for OD
|
||||||
|
#define OTYPER_PP(n) 0
|
||||||
|
#define OTYPER_OD(n) (1<<n)
|
||||||
|
|
||||||
|
// AFR field: afr - AFR number, pin - pin (0..15)
|
||||||
|
TRUE_INLINE uint32_t AFRf(uint8_t afr, uint8_t pin){
|
||||||
|
if(pin > 7) pin -= 8;
|
||||||
|
return (afr << (pin * 4));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/****************** FLASH Keys **********************************************/
|
/****************** FLASH Keys **********************************************/
|
||||||
|
|||||||
@@ -26,6 +26,9 @@
|
|||||||
#define WEAK __attribute__((weak))
|
#define WEAK __attribute__((weak))
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
extern uint32_t SysFreq;
|
||||||
|
|
||||||
void WEAK reset_handler(void);
|
void WEAK reset_handler(void);
|
||||||
void WEAK nmi_handler(void);
|
void WEAK nmi_handler(void);
|
||||||
void WEAK hard_fault_handler(void);
|
void WEAK hard_fault_handler(void);
|
||||||
|
|||||||
@@ -19,6 +19,8 @@
|
|||||||
*/
|
*/
|
||||||
#include "vector.h"
|
#include "vector.h"
|
||||||
|
|
||||||
|
uint32_t SysFreq = 8000000;
|
||||||
|
|
||||||
typedef void (*vector_table_entry_t)(void);
|
typedef void (*vector_table_entry_t)(void);
|
||||||
typedef void (*funcp_t) (void);
|
typedef void (*funcp_t) (void);
|
||||||
|
|
||||||
@@ -39,6 +41,7 @@ void null_handler(void);
|
|||||||
#define NVIC_IRQ_COUNT 32
|
#define NVIC_IRQ_COUNT 32
|
||||||
|
|
||||||
#if defined(STM32G070xx)
|
#if defined(STM32G070xx)
|
||||||
|
#define IRQ_HANDLERS \
|
||||||
[WWDG_IRQn] = wwdg_isr, \
|
[WWDG_IRQn] = wwdg_isr, \
|
||||||
[RTC_TAMP_IRQn] = rtc_isr, \
|
[RTC_TAMP_IRQn] = rtc_isr, \
|
||||||
[FLASH_IRQn] = flash_isr, \
|
[FLASH_IRQn] = flash_isr, \
|
||||||
|
|||||||
Reference in New Issue
Block a user