diff --git a/Makefile b/Makefile index 3f264a2..6c99d3d 100644 --- a/Makefile +++ b/Makefile @@ -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 diff --git a/adc.c b/adc.c new file mode 100644 index 0000000..f3e3491 --- /dev/null +++ b/adc.c @@ -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; +} diff --git a/adc.h b/adc.h new file mode 100644 index 0000000..2bb0f34 --- /dev/null +++ b/adc.h @@ -0,0 +1,10 @@ +#ifndef ADC_H +#define ADC_H +#include +#include +#include +#include + +void adc_setup(void); +uint32_t adc_bat_voltage(void); +#endif diff --git a/main.c b/main.c index 7460944..a2e369a 100644 --- a/main.c +++ b/main.c @@ -1,13 +1,103 @@ +#include +#include #include +#include +#include +#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); + } + } +} diff --git a/ringbuffer.c b/ringbuffer.c new file mode 100644 index 0000000..0dbb39b --- /dev/null +++ b/ringbuffer.c @@ -0,0 +1,89 @@ +#include "ringbuffer.h" +#include + +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; +} diff --git a/ringbuffer.h b/ringbuffer.h new file mode 100644 index 0000000..4cca110 --- /dev/null +++ b/ringbuffer.h @@ -0,0 +1,38 @@ +#ifndef RINGBUFFER_H +#define RINGBUFFER_H +#ifdef __cplusplus +extern "C" { +#endif +#include + +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 diff --git a/uart.c b/uart.c new file mode 100644 index 0000000..a8f4990 --- /dev/null +++ b/uart.c @@ -0,0 +1,24 @@ +#include "uart.h" +#include +#include +#include + +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); +} diff --git a/uart.h b/uart.h new file mode 100644 index 0000000..8a858cc --- /dev/null +++ b/uart.h @@ -0,0 +1,7 @@ +#ifndef UART_H +#define UART_H +#include + +void uart_setup(void); + +#endif diff --git a/usb.c b/usb.c index 7b36780..7342a43 100644 --- a/usb.c +++ b/usb.c @@ -7,10 +7,16 @@ #include #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() { } diff --git a/usb.h b/usb.h index d7041a8..ac27354 100644 --- a/usb.h +++ b/usb.h @@ -1,4 +1,14 @@ #ifndef USB_H #define USB_H +#include +#include + +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