Working uart bridging

This commit is contained in:
Lynn Ochs 2021-02-13 20:39:00 +01:00
parent 65b14f399a
commit 111c5f7200
10 changed files with 323 additions and 15 deletions

View File

@ -3,12 +3,13 @@ OOCD_INTERFACE ?= stlink-v2
OOCD_TARGET ?= stm32f4x
BMP_PORT ?= /dev/ttyBmpGdb
CFLAGS=-g -O0 -std=c99 -pedantic -Wall
CXXFLAGS=-g -O0 -std=c++17 -pedantic -Wall
CFLAGS=-g -O2 -std=c99 -pedantic -Wall
CXXFLAGS=-g -O2 -std=c++17 -pedantic -Wall
OBJS = usb.o
OBJS = usb.o adc.o ringbuffer.o uart.o
BINARY ?= main
DEVICE=STM32F405RG
#DEVICE=STM32F411CE
include ../rules.mk

26
adc.c Normal file
View File

@ -0,0 +1,26 @@
#include "adc.h"
static uint32_t bat_voltage_mv;
void adc_setup(void) {
rcc_periph_clock_enable(RCC_GPIOA);
rcc_periph_clock_enable(RCC_ADC1);
gpio_mode_setup(GPIOA, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, GPIO3);
adc_power_off(ADC1);
adc_disable_scan_mode(ADC1);
adc_set_sample_time_on_all_channels(ADC1, ADC_SMPR_SMP_480CYC);
adc_set_continuous_conversion_mode(ADC1);
uint8_t channel = 3;
adc_set_regular_sequence(ADC1, 1, &channel);
adc_power_on(ADC1);
adc_start_conversion_regular(ADC1);
}
uint32_t adc_bat_voltage(void) {
if (adc_get_flag(ADC1, ADC_SR_EOC)) {
bat_voltage_mv = adc_read_regular(ADC1);
}
return bat_voltage_mv;
}

10
adc.h Normal file
View File

@ -0,0 +1,10 @@
#ifndef ADC_H
#define ADC_H
#include <libopencm3/stm32/adc.h>
#include <libopencm3/stm32/gpio.h>
#include <libopencm3/stm32/rcc.h>
#include <stdint.h>
void adc_setup(void);
uint32_t adc_bat_voltage(void);
#endif

90
main.c
View File

@ -1,13 +1,103 @@
#include <libopencm3/cm3/nvic.h>
#include <libopencm3/cm3/systick.h>
#include <libopencm3/stm32/rcc.h>
#include <stddef.h>
#include <stdio.h>
#include "adc.h"
#include "usb.h"
#include "ringbuffer.h"
#include "uart.h"
volatile uint32_t tick = 0;
RINGBUFFER_STORAGE(usb_to_uart_buf, 64)
RINGBUFFER_STORAGE(uart_to_usb_buf, 64)
RINGBUFFER_STORAGE(comm_in_buf, 64)
RINGBUFFER_STORAGE(comm_out_buf, 64)
static void sys_tick_setup(void);
static void sys_tick_setup() {
systick_set_reload(168000);
systick_set_clocksource(STK_CSR_CLKSOURCE_AHB);
systick_counter_enable();
systick_interrupt_enable();
}
void sys_tick_handler() {
tick++;
}
int main(void) {
#if 0
rcc_clock_setup_pll(&rcc_hse_25mhz_3v3[RCC_CLOCK_3V3_84MHZ]);
#else
rcc_clock_setup_pll(&rcc_hse_12mhz_3v3[RCC_CLOCK_3V3_168MHZ]);
#endif
RINGBUFFER_INIT(uart_to_usb_buf, 64);
RINGBUFFER_INIT(usb_to_uart_buf, 64);
RINGBUFFER_INIT(comm_in_buf, 64);
RINGBUFFER_INIT(comm_out_buf, 64);
usb_setup();
adc_setup();
uart_setup();
sys_tick_setup();
nvic_enable_irq(NVIC_USART3_IRQ);
while (1) {
/* Handle control messages through the comms CDC */
char buf[64];
unsigned buf_len = 0;
for (char c; ringbuffer_get(comm_in_buf, (void*)&c, 1); ) {
switch (c) {
case 'B':
buf_len =
snprintf(buf, sizeof(buf), "%lu\r\n",
(unsigned long)adc_bat_voltage());
ringbuffer_add(comm_out_buf, buf, buf_len);
break;
}
}
/* Send replies */
if ((buf_len = ringbuffer_peek(comm_out_buf, &buf[0], sizeof buf))) {
if (usb_write_cdcacm(ACM_COMM, (void*)buf, buf_len, 1)) {
ringbuffer_skip(comm_out_buf, buf_len);
}
}
/* Send any available data to the NFC CDC */
if (!ringbuffer_empty(uart_to_usb_buf)) {
unsigned len = ringbuffer_peek(uart_to_usb_buf, &buf[0], sizeof buf);
if(usb_write_cdcacm(ACM_NFC, buf, len, 1)) {
ringbuffer_skip(uart_to_usb_buf, len);
}
}
if (!ringbuffer_empty(usb_to_uart_buf)) {
usart_enable_tx_interrupt(USART3);
}
usbd_poll(g_usbd_dev);
__asm__("wfi");
}
}
void usart3_isr() {
while (USART_SR(USART3) & USART_SR_RXNE) {
uint8_t c = usart_recv(USART3);
ringbuffer_add(uart_to_usb_buf, (void *)&c, 1);
}
while (USART_SR(USART3) & USART_SR_TXE) {
if (ringbuffer_empty(usb_to_uart_buf)) {
usart_disable_tx_interrupt(USART3);
break;
} else {
uint8_t c;
ringbuffer_get(usb_to_uart_buf, &c, 1);
usart_send(USART3, c);
}
}
}

89
ringbuffer.c Normal file
View File

@ -0,0 +1,89 @@
#include "ringbuffer.h"
#include <string.h>
unsigned ringbuffer_capacity(ringbuffer *buf) {
return buf->size;
}
unsigned ringbuffer_free(ringbuffer *buf) {
unsigned head = buf->head;
unsigned tail = buf->tail;
unsigned size = buf->size;
if (head >= tail) {
return size - (head - tail) - 1;
}
return tail - head - 1;
}
unsigned ringbuffer_level(ringbuffer *buf) {
unsigned head = buf->head;
unsigned tail = buf->tail;
if (head >= tail) {
return head - tail;
}
unsigned size = buf->size;
return size - tail + head;
}
unsigned ringbuffer_add(ringbuffer *buf, uint8_t *dat, unsigned len) {
unsigned rem = ringbuffer_free(buf);
unsigned head = buf->head;
unsigned written = 0;
const unsigned size = buf->size;
if (len > rem) {
len = rem;
}
if (head + len > size) {
written = size - head;
memcpy(buf->data + head, dat, written);
len -= written;
head = buf->head = 0;
dat += written;
}
memcpy(buf->data + head, dat, len);
buf->head = (head + len) % buf->size;
return written + len;
}
unsigned ringbuffer_empty(ringbuffer *buf) {
return buf->head == buf->tail;
}
unsigned ringbuffer_peek(ringbuffer *buf, uint8_t *dst, unsigned len) {
unsigned level = ringbuffer_level(buf);
unsigned size = buf->size;
unsigned tail = buf->tail;
unsigned written = 0;
if (len > level) {
len = level;
}
if (tail + len > size) {
written = size - tail;
memcpy(dst, buf->data + tail, written);
tail = 0;
dst += written;
len -= written;
}
memcpy(dst, buf->data + tail, len);
return len + written;
}
void ringbuffer_skip(ringbuffer *buf, unsigned len) {
buf->tail = (buf->tail + len) % (buf->size);
}
unsigned ringbuffer_get(ringbuffer *buf, uint8_t *dst, unsigned len) {
len = ringbuffer_peek(buf, dst, len);
ringbuffer_skip(buf, len);
return len;
}
void ringbuffer_rst(ringbuffer *buf) {
buf->head = buf->tail = 0;
}

38
ringbuffer.h Normal file
View File

@ -0,0 +1,38 @@
#ifndef RINGBUFFER_H
#define RINGBUFFER_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
typedef struct {
uint32_t head;
uint32_t tail;
uint32_t size;
uint8_t data[];
} ringbuffer;
#define RINGBUFFER_STORAGE(NAME, SIZE) uint8_t buf_##NAME##__LINE__[sizeof(ringbuffer) + SIZE]; ringbuffer *NAME = (ringbuffer*)buf_##NAME##__LINE__;
#define RINGBUFFER_INIT(NAME, SIZE) NAME->head = NAME->tail = 0; NAME->size = SIZE;
#define RINGBUFFER(NAME, SIZE) \
RINGBUFFER_STORAGE(NAME, SIZE); \
RINGBUFFER_INIT(NAME, SIZE);
void ringbuffer_rst(ringbuffer *buf);
unsigned ringbuffer_capacity(ringbuffer *buf);
unsigned ringbuffer_free(ringbuffer *buf);
unsigned ringbuffer_level(ringbuffer *buf);
unsigned ringbuffer_empty(ringbuffer *buf);
unsigned ringbuffer_add(ringbuffer *buf, uint8_t *dat, unsigned len);
unsigned ringbuffer_get(ringbuffer *buf, uint8_t *dst, unsigned len);
unsigned ringbuffer_peek(ringbuffer *buf, uint8_t *dst, unsigned len);
void ringbuffer_skip(ringbuffer *buf, unsigned len);
#ifdef __cplusplus
}
#endif
#endif

24
uart.c Normal file
View File

@ -0,0 +1,24 @@
#include "uart.h"
#include <libopencm3/cm3/nvic.h>
#include <libopencm3/stm32/rcc.h>
#include <libopencm3/stm32/gpio.h>
void uart_setup() {
rcc_periph_clock_enable(RCC_GPIOB);
rcc_periph_clock_enable(RCC_USART3);
gpio_mode_setup(GPIOB, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO10 | GPIO11);
gpio_set_af(GPIOB, GPIO_AF7, GPIO10 | GPIO11);
usart_set_baudrate(USART3, 115200);
usart_set_databits(USART3, 8);
usart_set_stopbits(USART3, USART_STOPBITS_1);
usart_set_mode(USART3, USART_MODE_TX_RX);
usart_set_parity(USART3, USART_PARITY_NONE);
usart_set_flow_control(USART3, USART_FLOWCONTROL_NONE);
usart_enable(USART3);
usart_disable_tx_complete_interrupt(USART3);
usart_enable_tx_interrupt(USART3);
usart_enable_rx_interrupt(USART3);
}

7
uart.h Normal file
View File

@ -0,0 +1,7 @@
#ifndef UART_H
#define UART_H
#include <libopencm3/stm32/usart.h>
void uart_setup(void);
#endif

37
usb.c
View File

@ -7,10 +7,16 @@
#include <stddef.h>
#include "usb.h"
#include "ringbuffer.h"
extern ringbuffer *usb_to_uart_buf, *comm_in_buf;
/* Number of serial devices we want to provide. */
#define NUM_SERIAL 2
static const uint8_t EP_COMM = 1 + 2 * ACM_COMM;
static const uint8_t EP_NFC = 1 + 2 * ACM_NFC;
/* CDC-ACM devices need a functional descriptor that looks like this */
struct usb_cdcacm_functional_descriptor {
struct usb_cdc_header_descriptor header;
@ -27,11 +33,11 @@ static char serial[24];
* In descriptors, indices are 1-based, and 0 is an empty string.
*/
static char const *usb_strings[] = {
"Imaginaerraum.de",
"DoorControl",
serial,
"RFID",
"Other"
"Imaginaerraum.de",
"DoorControl",
serial,
[3 + ACM_COMM] = "Comm",
[3 + ACM_NFC] = "RFID",
};
usbd_device *g_usbd_dev;
@ -135,14 +141,21 @@ static void cdcacm_data_rx_cb(usbd_device *usbd_dev, uint8_t ep)
/* Read some data from the endpoint */
int len = usbd_ep_read_packet(usbd_dev, ep, buf, 64);
if (len) {
/* Write it back */
while (usbd_ep_write_packet(usbd_dev, ep | 0x80, buf, len) == 0);
if (ep == EP_NFC) {
ringbuffer_add(usb_to_uart_buf, (void*)buf, len);
} else if (ep == EP_COMM) {
ringbuffer_add(comm_in_buf, (void*)buf, len);
}
}
static void cdcacm_set_config(usbd_device *usbd_dev, uint16_t wValue)
{
int usb_write_cdcacm(uint8_t acm, uint8_t *data, size_t len, int tries) {
int i = 0;
while (usbd_ep_write_packet(g_usbd_dev, (1 + 2 * acm) | 0x80, data, len) == 0 && ++i < tries)
;
return i < tries;
}
static void cdcacm_set_config(usbd_device *usbd_dev, uint16_t wValue) {
(void)wValue;
for (int i = 0; i < NUM_SERIAL; i++) {
@ -309,7 +322,7 @@ void usb_setup() {
usbd_register_set_config_callback(g_usbd_dev, cdcacm_set_config);
/* And use interrupts instead of polling. */
nvic_enable_irq(NVIC_OTG_FS_IRQ);
// nvic_enable_irq(NVIC_OTG_FS_IRQ);
}
void otg_fs_isr() { usbd_poll(g_usbd_dev); }
//void __attribute__((weak)) otg_fs_isr() { }

10
usb.h
View File

@ -1,4 +1,14 @@
#ifndef USB_H
#define USB_H
#include <libopencm3/usb/usbd.h>
#include <stddef.h>
extern usbd_device *g_usbd_dev;
void usb_setup(void);
int usb_write_cdcacm(uint8_t acm, uint8_t *data, size_t len, int tries);
#define ACM_NFC 1
#define ACM_COMM 0
#endif