serial WIP
This commit is contained in:
parent
f0291bc8e3
commit
ebb9c72384
14 changed files with 783 additions and 75 deletions
4
Makefile
4
Makefile
|
|
@ -34,6 +34,8 @@ C_SOURCES := src/main.c \
|
|||
src/adc.c \
|
||||
src/lcd.c \
|
||||
src/led.c \
|
||||
src/cobs.c \
|
||||
src/serial.c \
|
||||
src/usb_if.c \
|
||||
upstream/libusb_stm32/src/usbd_stm32l052_devfs.c \
|
||||
upstream/libusb_stm32/src/usbd_core.c
|
||||
|
|
@ -95,7 +97,7 @@ CFLAGS += -I$(CMSIS_DEVICE_DIR_ABS)/Include
|
|||
CFLAGS += $(ARCH_FLAGS) $(SYSTEM_FLAGS)
|
||||
CFLAGS += -fno-common -ffunction-sections -fdata-sections
|
||||
|
||||
COMMON_CFLAGS += -O$(OPT) -std=gnu11 -g
|
||||
COMMON_CFLAGS += -O$(OPT) -std=gnu2x -g
|
||||
COMMON_CFLAGS += $(DEVICE_DEFINES)
|
||||
COMMON_CFLAGS += -DDEBUG=$(DEBUG)
|
||||
|
||||
|
|
|
|||
|
|
@ -15,5 +15,6 @@ struct adc_state {
|
|||
extern struct adc_state st_adc;
|
||||
|
||||
void adc_init(void);
|
||||
void adc_dma_interrupt(uint32_t channel, uint32_t flags);
|
||||
|
||||
#endif /* __ADC_H__ */
|
||||
|
|
|
|||
23
include/cobs.h
Normal file
23
include/cobs.h
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
#ifndef __COBS_H__
|
||||
#define __COBS_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
struct cobs_decode_state {
|
||||
size_t p;
|
||||
size_t c;
|
||||
};
|
||||
|
||||
|
||||
ssize_t cobs_encode(char *dst, size_t dstlen, char *src, size_t srclen);
|
||||
ssize_t cobs_decode(char *dst, size_t dstlen, char *src, size_t srclen);
|
||||
|
||||
int cobs_encode_usart(int (*output)(char), char *src, size_t srclen);
|
||||
|
||||
void cobs_decode_incremental_initialize(struct cobs_decode_state *state);
|
||||
int cobs_decode_incremental(struct cobs_decode_state *state, char *dst, size_t dstlen, char src);
|
||||
|
||||
#endif//__COBS_H__
|
||||
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
|
|
@ -13,6 +14,10 @@
|
|||
#include <stm32f0xx.h>
|
||||
#include <core_cm0.h>
|
||||
|
||||
#define DMA1_Channel DMA1_Channel1
|
||||
#define DMA_ISR_FLAGS_Pos(channel) (4 * ((channel) - 1))
|
||||
#define DMA_ISR_FLAGS_CH(channel) (0xf << DMA_ISR_FLAGS_Pos(channel))
|
||||
|
||||
#define COUNT_OF(x) ((sizeof(x)/sizeof(0[x])) / ((size_t)(!(sizeof(x) % sizeof(0[x])))))
|
||||
|
||||
#define APB1_PRESC (1<<(APBPrescTable[(RCC->CFGR & RCC_CFGR_PPRE1_Msk) >> RCC_CFGR_PPRE1_Pos]))
|
||||
|
|
@ -24,6 +29,8 @@ enum ErrorCode {
|
|||
ERR_PHYSICAL_LAYER,
|
||||
ERR_PROTOCOL,
|
||||
ERR_DMA,
|
||||
ERR_BUSY,
|
||||
ERR_BUFFER_OVERFLOW,
|
||||
};
|
||||
typedef enum ErrorCode ErrorCode;
|
||||
|
||||
|
|
|
|||
|
|
@ -18,4 +18,6 @@ struct lcd_state {
|
|||
|
||||
extern struct lcd_state st_lcd;
|
||||
|
||||
void lcd_dma_interrupt(uint32_t channel, uint32_t flags);
|
||||
|
||||
#endif /* __LCD_H__ */
|
||||
|
|
|
|||
80
include/serial.h
Normal file
80
include/serial.h
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
#ifndef __SERIAL_H__
|
||||
#define __SERIAL_H__
|
||||
|
||||
#include <global.h>
|
||||
#include <cobs.h>
|
||||
|
||||
struct dma_tx_buf {
|
||||
/* The following fields are accessed only from DMA ISR */
|
||||
ssize_t xfr_start; /* Start index of running DMA transfer */
|
||||
ssize_t xfr_end; /* End index of running DMA transfer plus one */
|
||||
bool wraparound;
|
||||
ssize_t xfr_next;
|
||||
bool ack;
|
||||
|
||||
|
||||
/* The following fields are written only from non-interrupt code */
|
||||
ssize_t wr_pos; /* Next index to be written */
|
||||
ssize_t wr_idx;
|
||||
ssize_t packet_end[8];
|
||||
|
||||
/* The following may be accessed by anything */
|
||||
uint8_t data[512];
|
||||
};
|
||||
|
||||
struct uart_dma_state {
|
||||
struct dma_tx_buf tx_buf;
|
||||
|
||||
uint32_t tx_overruns, rx_overruns;
|
||||
uint32_t rx_framing_errors, rx_protocol_errors;
|
||||
uint32_t retransmissions, packet_count;
|
||||
ErrorCode error;
|
||||
|
||||
struct cobs_decode_state cobs_state;
|
||||
|
||||
size_t tx_dma_ch;
|
||||
USART_TypeDef *usart;
|
||||
|
||||
uint8_t rx_buf[32];
|
||||
uint8_t addr;
|
||||
};
|
||||
|
||||
struct __attribute__((__packed__)) ll_pkt {
|
||||
uint32_t crc32;
|
||||
/* CRC computed over entire packet starting here */
|
||||
uint8_t src;
|
||||
uint8_t dst;
|
||||
uint8_t pid;
|
||||
uint8_t type;
|
||||
uint8_t data[0];
|
||||
};
|
||||
|
||||
enum ctrl_pkt_type {
|
||||
CTRL_PKT_RESET = 1,
|
||||
CTRL_PKT_ACK = 2,
|
||||
CTRL_PKT_NACK = 3,
|
||||
CTRL_PKT_PING = 4,
|
||||
CTRL_PKT_PONG = 5,
|
||||
_USER_PKT_START = 16,
|
||||
};
|
||||
|
||||
enum user_pkt_type {
|
||||
USER_PKT_ADC_DATA = _USER_PKT_START+0,
|
||||
USER_PKT_SET_DISPLAY = _USER_PKT_START+1,
|
||||
};
|
||||
|
||||
struct __attribute__((__packed__)) user_pkt_adc_data {
|
||||
struct ll_pkt hdr;
|
||||
uint8_t adc_data_packed[3*2*16];
|
||||
};
|
||||
|
||||
extern volatile struct uart_dma_state uart_st;
|
||||
|
||||
void uart_dma_init(USART_TypeDef *usart, int tx_dma_ch, int addr);
|
||||
int uart_send_packet_nonblocking(struct ll_pkt *pkt, size_t pkt_len);
|
||||
int uart_ack_packet(uint8_t idx);
|
||||
void uart_dma_interrupt(uint32_t channel, uint32_t flags);
|
||||
void uart_interrupt(uint32_t isr);
|
||||
extern void uart_handle_user_packet(struct ll_pkt *pkt, size_t len);
|
||||
|
||||
#endif // __SERIAL_H__
|
||||
|
|
@ -2,7 +2,28 @@
|
|||
#define __USB_IF_H__
|
||||
|
||||
#include <global.h>
|
||||
#include <usb_cdc.h>
|
||||
#include <usb.h>
|
||||
#include <cobs.h>
|
||||
|
||||
#define USB_CDC_DATA_SIZE 0x40
|
||||
|
||||
struct usb_state {
|
||||
struct usb_cdc_line_coding line;
|
||||
usbd_device usb_dev;
|
||||
uint32_t usb_buf[0x20];
|
||||
uint8_t usb_pkbuf[USB_CDC_DATA_SIZE];
|
||||
struct cobs_decode_state cobs_state;
|
||||
bool cobs_synchronized;
|
||||
ErrorCode error;
|
||||
uint8_t txbuf[USB_CDC_DATA_SIZE];
|
||||
size_t txpos;
|
||||
};
|
||||
|
||||
extern struct usb_state st_usb;
|
||||
|
||||
void usb_init(void);
|
||||
extern void handle_usb_packet(void *packet, size_t len);
|
||||
ErrorCode usb_write_response(void *data, size_t len);
|
||||
|
||||
#endif /* __USB_IF_H__ */
|
||||
|
|
|
|||
23
include/usb_proto.h
Normal file
23
include/usb_proto.h
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
#ifndef __USB_PROTO_H__
|
||||
#define __USB_PROTO_H__
|
||||
|
||||
#include <global.h>
|
||||
|
||||
enum usbp_pkt_type {
|
||||
USBP_GET_STATUS = 0,
|
||||
USBP_GET_MEASUREMENTS = 1,
|
||||
};
|
||||
|
||||
struct __attribute__((__packed__)) usbp_status_pkt {
|
||||
uint8_t packet_type;
|
||||
uint8_t has_lcd;
|
||||
uint8_t has_adc;
|
||||
};
|
||||
|
||||
struct __attribute__((__packed__)) usbp_measurement_pkt {
|
||||
uint8_t packet_type;
|
||||
uint8_t num_channels;
|
||||
uint32_t measurements[32];
|
||||
};
|
||||
|
||||
#endif /* __USB_PROTO_H__ */
|
||||
17
src/adc.c
17
src/adc.c
|
|
@ -142,22 +142,11 @@ void adc_init() {
|
|||
TIM2->SMCR = TIM_SMCR_ETP | (7<<TIM_SMCR_TS_Pos) | (6<<TIM_SMCR_SMS_Pos);
|
||||
}
|
||||
|
||||
void DMA1_Channel1_IRQHandler() {
|
||||
int flags = DMA1->ISR;
|
||||
if (flags & (DMA_ISR_TEIF1)) {
|
||||
DMA1->IFCR = DMA_IFCR_CTEIF1;
|
||||
st_adc.error = ERR_DMA;
|
||||
}
|
||||
}
|
||||
|
||||
void DMA1_Channel2_3_IRQHandler() {
|
||||
int flags = DMA1->ISR;
|
||||
if (flags & (DMA_ISR_TEIF2 | DMA_ISR_TEIF3)) {
|
||||
DMA1->IFCR = DMA_IFCR_CTEIF2 | DMA_IFCR_CTEIF3;
|
||||
void adc_dma_interrupt(uint32_t channel, uint32_t flags) {
|
||||
if (flags & DMA_ISR_TEIF1) {
|
||||
st_adc.error = ERR_DMA;
|
||||
|
||||
} else if (flags & DMA_ISR_TCIF2) {
|
||||
DMA1->IFCR = DMA_IFCR_CTCIF2;
|
||||
} else if (flags & DMA_ISR_TCIF1 && channel == 3) {
|
||||
DMA1_Channel3->CCR &= ~DMA_CCR_EN;
|
||||
|
||||
if ((st_adc.rxbuf[0] & 0x3) != 0x1) {
|
||||
|
|
|
|||
212
src/cobs.c
Normal file
212
src/cobs.c
Normal file
|
|
@ -0,0 +1,212 @@
|
|||
|
||||
#include "serial.h"
|
||||
#include "cobs.h"
|
||||
|
||||
int cobs_encode_usart(int (*output)(char), char *src, size_t srclen) {
|
||||
if (srclen > 254)
|
||||
return ERR_BUFFER_OVERFLOW;
|
||||
|
||||
size_t p = 0;
|
||||
while (p <= srclen) {
|
||||
|
||||
char val;
|
||||
if (p != 0 && src[p-1] != 0) {
|
||||
val = src[p-1];
|
||||
|
||||
} else {
|
||||
size_t q = p;
|
||||
while (q < srclen && src[q] != 0)
|
||||
q++;
|
||||
val = (char)q-p+1;
|
||||
}
|
||||
|
||||
int rv = output(val);
|
||||
if (rv)
|
||||
return rv;
|
||||
p++;
|
||||
}
|
||||
|
||||
int rv = output(0);
|
||||
if (rv)
|
||||
return rv;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*@ requires \valid(dst + (0..dstlen-1));
|
||||
@ requires \valid_read(src + (0..srclen-1));
|
||||
@ requires \separated(dst + (0..dstlen-1), src + (0..srclen-1));
|
||||
@
|
||||
@ behavior maybe_valid_frame:
|
||||
@ assumes 1 <= srclen <= dstlen <= 65535;
|
||||
@ assumes \exists integer j; j > 0 && \forall integer i; 0 <= i < j ==> src[i] != 0;
|
||||
@ assumes \exists integer i; 0 <= i < srclen && src[i] == 0;
|
||||
@ assigns dst[0..dstlen-1];
|
||||
@ ensures \result >= 0 || \result == -3;
|
||||
@ ensures \result >= 0 ==> src[\result+1] == 0;
|
||||
@ ensures \result >= 0 ==> (\forall integer i; 0 <= i < \result ==> src[i] != 0);
|
||||
@
|
||||
@ behavior invalid_frame:
|
||||
@ assumes 1 <= srclen <= dstlen <= 65535;
|
||||
@ assumes src[0] == 0 || \forall integer i; 0 <= i < srclen ==> src[i] != 0;
|
||||
@ assigns dst[0..dstlen-1];
|
||||
@ ensures \result == -2;
|
||||
@
|
||||
@ behavior invalid_buffers:
|
||||
@ assumes dstlen < 0 || dstlen > 65535
|
||||
@ || srclen < 1 || srclen > 65535
|
||||
@ || dstlen < srclen;
|
||||
@ assigns \nothing;
|
||||
@ ensures \result == -1;
|
||||
@
|
||||
@ complete behaviors;
|
||||
@ disjoint behaviors;
|
||||
@*/
|
||||
ssize_t cobs_decode(char *dst, size_t dstlen, char *src, size_t srclen) {
|
||||
if (dstlen > 65535 || srclen > 65535)
|
||||
return -1;
|
||||
|
||||
if (srclen < 1)
|
||||
return -1;
|
||||
|
||||
if (dstlen < srclen)
|
||||
return -1;
|
||||
|
||||
size_t p = 1;
|
||||
size_t c = (unsigned char)src[0];
|
||||
//@ assert 0 <= c < 256;
|
||||
//@ assert 0 <= c;
|
||||
//@ assert c < 256;
|
||||
if (c == 0)
|
||||
return -2; /* invalid framing. An empty frame would be [...] 00 01 00, not [...] 00 00 */
|
||||
//@ assert c >= 0;
|
||||
//@ assert c != 0;
|
||||
//@ assert c <= 257;
|
||||
//@ assert c > 0;
|
||||
//@ assert c >= 0 && c != 0 ==> c > 0;
|
||||
|
||||
/*@ //loop invariant \forall integer i; 0 <= i <= p ==> (i == srclen || src[i] != 0);
|
||||
@ loop invariant \forall integer i; 1 <= i < p ==> src[i] != 0;
|
||||
@ loop invariant c > 0;
|
||||
@ loop invariant 1 <= p <= srclen <= dstlen <= 65535;
|
||||
@ loop invariant \separated(dst + (0..dstlen-1), src + (0..srclen-1));
|
||||
@ loop invariant \valid_read(src + (0..srclen-1));
|
||||
@ loop invariant \forall integer i; 1 <= i <= srclen ==> \valid(dst + i - 1);
|
||||
@ loop assigns dst[0..dstlen-1], p, c;
|
||||
@ loop variant srclen-p;
|
||||
@*/
|
||||
while (p < srclen && src[p]) {
|
||||
char val;
|
||||
c--;
|
||||
|
||||
//@ assert src[p] != 0;
|
||||
if (c == 0) {
|
||||
c = (unsigned char)src[p];
|
||||
val = 0;
|
||||
} else {
|
||||
val = src[p];
|
||||
}
|
||||
|
||||
//@ assert 0 <= p-1 <= dstlen-1;
|
||||
dst[p-1] = val;
|
||||
p++;
|
||||
}
|
||||
|
||||
if (p == srclen)
|
||||
return -2; /* Invalid framing. The terminating null byte should always be present in the input buffer. */
|
||||
|
||||
if (c != 1)
|
||||
return -3; /* Invalid framing. The skip counter does not hit the end of the frame. */
|
||||
|
||||
//@ assert 0 < p <= srclen <= 65535;
|
||||
//@ assert src[p] == 0;
|
||||
//@ assert \forall integer i; 1 <= i < p ==> src[i] != 0;
|
||||
return p-1;
|
||||
}
|
||||
|
||||
void cobs_decode_incremental_initialize(struct cobs_decode_state *state) {
|
||||
state->p = 0;
|
||||
state->c = 0;
|
||||
}
|
||||
|
||||
int cobs_decode_incremental(struct cobs_decode_state *state, char *dst, size_t dstlen, char src) {
|
||||
if (state->p == 0) {
|
||||
if (src == 0)
|
||||
goto empty_errout; /* invalid framing. An empty frame would be [...] 00 01 00, not [...] 00 00 */
|
||||
state->c = (unsigned char)src;
|
||||
state->p++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!src) {
|
||||
if (state->c != 1)
|
||||
goto errout; /* Invalid framing. The skip counter does not hit the end of the frame. */
|
||||
int rv = state->p-1;
|
||||
cobs_decode_incremental_initialize(state);
|
||||
return rv;
|
||||
}
|
||||
|
||||
char val;
|
||||
state->c--;
|
||||
|
||||
if (state->c == 0) {
|
||||
state->c = (unsigned char)src;
|
||||
val = 0;
|
||||
} else {
|
||||
val = src;
|
||||
}
|
||||
|
||||
size_t pos = state->p-1;
|
||||
if (pos >= dstlen)
|
||||
return -2; /* output buffer too small */
|
||||
dst[pos] = val;
|
||||
state->p++;
|
||||
return 0;
|
||||
|
||||
errout:
|
||||
cobs_decode_incremental_initialize(state);
|
||||
return -1;
|
||||
|
||||
empty_errout:
|
||||
cobs_decode_incremental_initialize(state);
|
||||
return -3;
|
||||
}
|
||||
|
||||
#ifdef VALIDATION
|
||||
/*@
|
||||
@ requires 0 <= d < 256;
|
||||
@ assigns \nothing;
|
||||
@*/
|
||||
size_t test(char foo, unsigned int d) {
|
||||
unsigned int c = (unsigned char)foo;
|
||||
if (c != 0) {
|
||||
//@ assert c < 256;
|
||||
//@ assert c >= 0;
|
||||
//@ assert c != 0;
|
||||
//@ assert c > 0;
|
||||
}
|
||||
if (d != 0) {
|
||||
//@ assert d >= 0;
|
||||
//@ assert d != 0;
|
||||
//@ assert d > 0;
|
||||
}
|
||||
return c + d;
|
||||
}
|
||||
|
||||
#include <__fc_builtin.h>
|
||||
|
||||
void main(void) {
|
||||
char inbuf[254];
|
||||
char cobsbuf[256];
|
||||
char outbuf[256];
|
||||
|
||||
size_t range = Frama_C_interval(0, sizeof(inbuf));
|
||||
Frama_C_make_unknown((char *)inbuf, range);
|
||||
|
||||
cobs_encode(cobsbuf, sizeof(cobsbuf), inbuf, sizeof(inbuf));
|
||||
cobs_decode(outbuf, sizeof(outbuf), cobsbuf, sizeof(cobsbuf));
|
||||
|
||||
//@ assert \forall integer i; 0 <= i < sizeof(inbuf) ==> outbuf[i] == inbuf[i];
|
||||
}
|
||||
#endif//VALIDATION
|
||||
|
||||
|
|
@ -195,15 +195,12 @@ void lcd_init() {
|
|||
st_lcd.led = true;
|
||||
}
|
||||
|
||||
void DMA1_Channel4_5_6_7_IRQHandler() {
|
||||
int flags = DMA1->ISR;
|
||||
if (flags & (DMA_ISR_TEIF5 | DMA_ISR_TEIF6 | DMA_ISR_TEIF7)) {
|
||||
DMA1->IFCR = DMA_IFCR_CTEIF5 | DMA_IFCR_CTEIF6 | DMA_IFCR_CTEIF7;
|
||||
void lcd_dma_interrupt(uint32_t channel, uint32_t flags) {
|
||||
if (flags & DMA_ISR_TEIF1) {
|
||||
st_lcd.error = ERR_DMA;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void I2C1_IRQHandler() {
|
||||
int flags = I2C1->ISR;
|
||||
if (flags & (I2C_ISR_ARLO | I2C_ISR_BERR)) {
|
||||
|
|
|
|||
115
src/main.c
115
src/main.c
|
|
@ -2,9 +2,11 @@
|
|||
#include <global.h>
|
||||
|
||||
#include <adc.h>
|
||||
#include <serial.h>
|
||||
#include <lcd.h>
|
||||
#include <led.h>
|
||||
#include <usb_if.h>
|
||||
#include <usb_proto.h>
|
||||
|
||||
#define AFRL(pin, val) ((val) << ((pin)*4))
|
||||
#define AFRH(pin, val) ((val) << (((pin)-8)*4))
|
||||
|
|
@ -213,7 +215,7 @@ int main(void) {
|
|||
;
|
||||
|
||||
/* Enable peripheral clocks */
|
||||
RCC->AHBENR |= RCC_AHBENR_GPIOAEN | RCC_AHBENR_GPIOBEN | RCC_AHBENR_GPIOCEN | RCC_AHBENR_DMAEN;
|
||||
RCC->AHBENR |= RCC_AHBENR_GPIOAEN | RCC_AHBENR_GPIOBEN | RCC_AHBENR_GPIOCEN | RCC_AHBENR_DMAEN | RCC_AHBENR_CRCEN;
|
||||
RCC->APB2ENR |= RCC_APB2ENR_TIM16EN | RCC_APB2ENR_USART1EN | RCC_APB2ENR_SPI1EN | RCC_APB2ENR_ADCEN | RCC_APB2ENR_TIM15EN | RCC_APB2ENR_SYSCFGEN | RCC_APB2ENR_TIM17EN;
|
||||
RCC->APB1ENR |= RCC_APB1ENR_TIM2EN | RCC_APB1ENR_TIM3EN | RCC_APB1ENR_SPI2EN | RCC_APB1ENR_USART3EN | RCC_APB1ENR_I2C1EN | RCC_APB1ENR_USBEN | RCC_APB1ENR_CRSEN;
|
||||
RCC->CFGR3 |= RCC_CFGR3_I2C1SW;
|
||||
|
|
@ -323,6 +325,7 @@ int main(void) {
|
|||
lcd_init();
|
||||
|
||||
if (st_lcd.has_lcd) {
|
||||
uart_dma_init(USART3, 2, 2);
|
||||
const char *lines[4] = {"LINE 1 LINE 1 LINE 1",
|
||||
"LINE 2 LINE 2 LINE 2",
|
||||
"LINE 3 LINE 3 LINE 3",
|
||||
|
|
@ -334,6 +337,7 @@ int main(void) {
|
|||
board_config = BCFG_DISPLAY;
|
||||
board_addr = 1;
|
||||
} else {
|
||||
uart_dma_init(USART3, 7, 1);
|
||||
int bt = bt_inputs();
|
||||
if (bt&0) {
|
||||
board_config = BCFG_MOTOR;
|
||||
|
|
@ -351,22 +355,14 @@ int main(void) {
|
|||
SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk | SysTick_CTRL_TICKINT_Msk | SysTick_CTRL_ENABLE_Msk;
|
||||
NVIC_EnableIRQ(SysTick_IRQn);
|
||||
|
||||
// int apb2_clock = SystemCoreClock / APB2_PRESC;
|
||||
//
|
||||
// TIM15->PSC = apb2_clock / 1000000 * 100 - 1; /* 100us ticks */
|
||||
// TIM15->ARR = 1000 - 1; /* 100ms overflow interrupt interval */
|
||||
// TIM15->DIER = TIM_DIER_UIE;
|
||||
// TIM15->CR1 = TIM_CR1_CEN;
|
||||
// NVIC_EnableIRQ(TIM1_BRK_TIM15_IRQn);
|
||||
//
|
||||
// int baudrate = 115200;
|
||||
//
|
||||
// USART1->CR1 = USART_CR1_TE | USART_CR1_RE;
|
||||
// USART1->BRR = (apb2_clock + baudrate/2) / baudrate;
|
||||
// USART1->CR2 |= USART_CR2_RXINV; //| USART_CR2_TXINV;
|
||||
// USART1->CR1 |= USART_CR1_UE;
|
||||
//
|
||||
// USART1->TDR = 0; /* Kick off transmission */
|
||||
/* Either for UART or ADC */
|
||||
NVIC_EnableIRQ(DMA1_Channel2_3_IRQn);
|
||||
NVIC_SetPriority(DMA1_Channel2_3_IRQn, 2<<5);
|
||||
|
||||
/* UART receive interrupt */
|
||||
NVIC_EnableIRQ(USART3_4_IRQn);
|
||||
NVIC_SetPriority(USART3_4_IRQn, 1<<5);
|
||||
|
||||
for (size_t i=0; i<10; i++) {
|
||||
st_led.led[i].r = i*10;
|
||||
st_led.led[i].g = i*20;
|
||||
|
|
@ -402,6 +398,83 @@ void SysTick_Handler() {
|
|||
decimal_7seg(1, sys_time_s, 0);
|
||||
}
|
||||
|
||||
void handle_usb_packet(void *packet, size_t len) {
|
||||
switch (*(uint8_t *)packet) {
|
||||
case USBP_GET_STATUS: {
|
||||
struct usbp_status_pkt response = {
|
||||
.packet_type = USBP_GET_STATUS,
|
||||
.has_adc = st_adc.has_adc,
|
||||
.has_lcd = st_lcd.has_lcd,
|
||||
};
|
||||
usb_write_response(&response, sizeof(response));
|
||||
break;
|
||||
}
|
||||
|
||||
case USBP_GET_MEASUREMENTS: {
|
||||
struct usbp_measurement_pkt response = {
|
||||
.packet_type = USBP_GET_MEASUREMENTS,
|
||||
};
|
||||
usb_write_response(&response, sizeof(response));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void uart_handle_user_packet(struct ll_pkt *pkt, size_t len) {
|
||||
}
|
||||
|
||||
void DMA1_Channel2_3_IRQHandler() {
|
||||
int flags = DMA1->ISR;
|
||||
DMA1->IFCR = DMA_IFCR_CGIF2 | DMA_IFCR_CGIF3;
|
||||
|
||||
if (flags & DMA_ISR_FLAGS_CH(2)) {
|
||||
if (st_adc.has_adc) {
|
||||
adc_dma_interrupt(2, flags>>DMA_ISR_FLAGS_Pos(2));
|
||||
} else {
|
||||
uart_dma_interrupt(2, flags>>DMA_ISR_FLAGS_Pos(2));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (flags & DMA_ISR_FLAGS_CH(3)) {
|
||||
if (st_adc.has_adc) {
|
||||
adc_dma_interrupt(3, flags>>DMA_ISR_FLAGS_Pos(3));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DMA1_Channel4_5_6_7_IRQHandler() {
|
||||
int flags = DMA1->ISR;
|
||||
DMA1->IFCR = DMA_IFCR_CGIF4 | DMA_IFCR_CGIF5 | DMA_IFCR_CGIF6 | DMA_IFCR_CGIF7;
|
||||
|
||||
if (flags & DMA_ISR_FLAGS_CH(6)) {
|
||||
if (st_lcd.has_lcd) {
|
||||
lcd_dma_interrupt(6, flags>>DMA_ISR_FLAGS_Pos(6));
|
||||
}
|
||||
}
|
||||
|
||||
if (flags & DMA_ISR_FLAGS_CH(7)) {
|
||||
if (st_lcd.has_lcd) {
|
||||
lcd_dma_interrupt(6, flags>>DMA_ISR_FLAGS_Pos(7));
|
||||
} else {
|
||||
uart_dma_interrupt(7, flags>>DMA_ISR_FLAGS_Pos(7));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DMA1_Channel1_IRQHandler() {
|
||||
int flags = DMA1->ISR;
|
||||
if (flags & DMA_ISR_TEIF1) {
|
||||
adc_dma_interrupt(1, flags>DMA_ISR_FLAGS_Pos(1));
|
||||
}
|
||||
}
|
||||
|
||||
void USART3_4_IRQHandler() {
|
||||
uint32_t isr = USART3->ISR;
|
||||
USART3->ICR = isr;
|
||||
uart_interrupt(isr);
|
||||
}
|
||||
|
||||
void HardFault_Handler() {
|
||||
asm volatile ("bkpt");
|
||||
}
|
||||
|
|
@ -425,7 +498,15 @@ void *memcpy(void *restrict dest, const void *restrict src, size_t n)
|
|||
|
||||
void *memmove(void *dest, const void *src, size_t n)
|
||||
{
|
||||
<<<<<<< HEAD
|
||||
return memcpy(dest, src, n);
|
||||
=======
|
||||
unsigned char *d = dest;
|
||||
const unsigned char *s = src;
|
||||
|
||||
for (; n; n--) *d++ = *s++;
|
||||
return dest;
|
||||
>>>>>>> e6841f8 (serial WIP)
|
||||
}
|
||||
|
||||
void *memset(void *dest, int c, size_t n)
|
||||
|
|
|
|||
246
src/serial.c
Normal file
246
src/serial.c
Normal file
|
|
@ -0,0 +1,246 @@
|
|||
#include <global.h>
|
||||
#include <serial.h>
|
||||
#include <cobs.h>
|
||||
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
volatile struct uart_dma_state uart_st;
|
||||
|
||||
static void uart_schedule_dma(bool retransmit);
|
||||
static int uart_putc_nonblocking(uint8_t c);
|
||||
static void uart_dma_reset(void);
|
||||
|
||||
|
||||
void uart_dma_reset() {
|
||||
memset((void *)&uart_st, 0, sizeof(uart_st));
|
||||
uart_st.tx_buf.xfr_start = -1;
|
||||
|
||||
for (size_t i=0; i<COUNT_OF(uart_st.tx_buf.packet_end); i++)
|
||||
uart_st.tx_buf.packet_end[i] = -1;
|
||||
|
||||
cobs_decode_incremental_initialize((struct cobs_decode_state *)&uart_st.cobs_state);
|
||||
}
|
||||
|
||||
void uart_dma_init(USART_TypeDef *usart, int tx_dma_ch, int addr) {
|
||||
uart_dma_reset();
|
||||
uart_st.tx_dma_ch = tx_dma_ch;
|
||||
uart_st.usart = usart;
|
||||
uart_st.addr = addr;
|
||||
|
||||
/* Configure DMA 1 Channel 2 to handle uart transmission */
|
||||
DMA1_Channel[uart_st.tx_dma_ch].CPAR = (uint32_t)&(USART1->TDR);
|
||||
DMA1_Channel[uart_st.tx_dma_ch].CCR = (0<<DMA_CCR_PL_Pos)
|
||||
| DMA_CCR_DIR
|
||||
| (0<<DMA_CCR_MSIZE_Pos) /* 8 bit */
|
||||
| (0<<DMA_CCR_PSIZE_Pos) /* 8 bit */
|
||||
| DMA_CCR_MINC
|
||||
| DMA_CCR_TCIE; /* Enable transfer complete interrupt. */
|
||||
|
||||
usart->CR1 = /* 8-bit -> M1, M0 clear */
|
||||
/* OVER8 clear. Use default 16x oversampling */
|
||||
/* CMIF clear */
|
||||
USART_CR1_MME
|
||||
/* WAKE clear */
|
||||
/* PCE, PS clear */
|
||||
| USART_CR1_RXNEIE /* Enable receive interrupt */
|
||||
/* other interrupts clear */
|
||||
| USART_CR1_TE
|
||||
| USART_CR1_RE;
|
||||
/* Set baudrate */
|
||||
usart->BRR = 192; /* 250kBd */
|
||||
usart->CR3 |= USART_CR3_DMAT; /* TX DMA enable */
|
||||
|
||||
/* And... go! */
|
||||
usart->CR1 |= USART_CR1_UE;
|
||||
}
|
||||
|
||||
void uart_interrupt(uint32_t isr) {
|
||||
if (isr & USART_ISR_ORE) {
|
||||
uart_st.rx_overruns++;
|
||||
return;
|
||||
}
|
||||
|
||||
if (isr & USART_ISR_RXNE) {
|
||||
uint8_t c = uart_st.usart->RDR;
|
||||
|
||||
int rc = cobs_decode_incremental((struct cobs_decode_state *)&uart_st.cobs_state, (char *)&uart_st.rx_buf, sizeof(uart_st.rx_buf), c);
|
||||
if (rc == 0) /* packet still incomplete */
|
||||
return;
|
||||
|
||||
if (rc < 0) {
|
||||
uart_st.rx_framing_errors++;
|
||||
return;
|
||||
}
|
||||
|
||||
/* A complete frame received */
|
||||
if (rc < (int)sizeof(struct ll_pkt)) {
|
||||
uart_st.rx_protocol_errors++;
|
||||
return;
|
||||
}
|
||||
|
||||
volatile struct ll_pkt *pkt = (volatile struct ll_pkt *)&uart_st.rx_buf;
|
||||
|
||||
if (pkt->dst != uart_st.addr && pkt->dst != 0xff) {
|
||||
/* we are not addressed */
|
||||
return;
|
||||
}
|
||||
|
||||
switch (pkt->type) {
|
||||
case CTRL_PKT_RESET:
|
||||
uart_dma_reset();
|
||||
break;
|
||||
|
||||
case CTRL_PKT_ACK:
|
||||
if (!(DMA1_Channel[uart_st.tx_dma_ch].CCR & DMA_CCR_EN))
|
||||
uart_schedule_dma(false);
|
||||
break;
|
||||
|
||||
case CTRL_PKT_NACK:
|
||||
if (!(DMA1_Channel[uart_st.tx_dma_ch].CCR & DMA_CCR_EN))
|
||||
uart_schedule_dma(true);
|
||||
break;
|
||||
|
||||
case CTRL_PKT_PING: {
|
||||
struct ll_pkt reply = {
|
||||
.src = uart_st.addr,
|
||||
.dst = pkt->src,
|
||||
.pid = pkt->pid,
|
||||
.type = CTRL_PKT_PONG,
|
||||
};
|
||||
|
||||
rc = uart_send_packet_nonblocking(&reply, sizeof(reply));
|
||||
if (rc) {
|
||||
uart_st.error = rc;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
if (pkt->type < _USER_PKT_START) {
|
||||
uart_st.rx_protocol_errors++;
|
||||
} else {
|
||||
uart_handle_user_packet((struct ll_pkt *)pkt, rc);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void uart_schedule_dma(bool retransmit) {
|
||||
volatile struct dma_tx_buf *buf = &uart_st.tx_buf;
|
||||
|
||||
ssize_t xfr_start, xfr_end, xfr_len;
|
||||
if (buf->wraparound) {
|
||||
buf->wraparound = false;
|
||||
xfr_start = 0;
|
||||
xfr_len = buf->xfr_end;
|
||||
xfr_end = buf->xfr_end;
|
||||
|
||||
} else if (!retransmit) {
|
||||
if (buf->packet_end[buf->xfr_next] == -1)
|
||||
return; /* Nothing to transmit */
|
||||
|
||||
xfr_start = buf->xfr_end;
|
||||
xfr_end = buf->packet_end[buf->xfr_next];
|
||||
buf->packet_end[buf->xfr_next] = -1;
|
||||
buf->xfr_next = (buf->xfr_next + 1) % COUNT_OF(buf->packet_end);
|
||||
|
||||
if (xfr_end > xfr_start) { /* no wraparound */
|
||||
xfr_len = xfr_end - xfr_start;
|
||||
|
||||
} else { /* wraparound */
|
||||
if (xfr_end != 0)
|
||||
buf->wraparound = true;
|
||||
xfr_len = sizeof(buf->data) - xfr_start;
|
||||
}
|
||||
|
||||
} else {
|
||||
/* retransmit */
|
||||
/* First, send a zero to delimit any garbage from the following good packet */
|
||||
uart_st.usart->TDR = 0x00;
|
||||
|
||||
xfr_start = buf->xfr_start;
|
||||
xfr_end = buf->xfr_end;
|
||||
|
||||
if (xfr_end > xfr_start) { /* no wraparound */
|
||||
xfr_len = xfr_end - xfr_start;
|
||||
|
||||
} else { /* wraparound */
|
||||
if (xfr_end != 0)
|
||||
buf->wraparound = true;
|
||||
xfr_len = sizeof(buf->data) - xfr_start;
|
||||
}
|
||||
|
||||
uart_st.retransmissions++;
|
||||
}
|
||||
|
||||
buf->xfr_start = xfr_start;
|
||||
buf->xfr_end = xfr_end;
|
||||
|
||||
/* initiate transmission of new buffer */
|
||||
DMA1_Channel[uart_st.tx_dma_ch].CMAR = (uint32_t)(buf->data + xfr_start);
|
||||
DMA1_Channel[uart_st.tx_dma_ch].CNDTR = xfr_len;
|
||||
DMA1_Channel[uart_st.tx_dma_ch].CCR |= DMA_CCR_EN;
|
||||
}
|
||||
|
||||
int uart_putc_nonblocking(uint8_t c) {
|
||||
volatile struct dma_tx_buf *buf = &uart_st.tx_buf;
|
||||
|
||||
if (buf->wr_pos == buf->xfr_start)
|
||||
return ERR_BUSY;
|
||||
|
||||
buf->data[buf->wr_pos] = c;
|
||||
buf->wr_pos = (buf->wr_pos + 1) % sizeof(buf->data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void uart_dma_interrupt(uint32_t channel, uint32_t flags) {
|
||||
DMA1_Channel[uart_st.tx_dma_ch].CCR &= ~DMA_CCR_EN;
|
||||
|
||||
if (flags & DMA_ISR_TEIF1) {
|
||||
uart_st.error = ERR_DMA;
|
||||
|
||||
} else if (flags & DMA_ISR_TCIF1 && channel == uart_st.tx_dma_ch) {
|
||||
/* Wait for channel to turn off */
|
||||
while (DMA1_Channel[uart_st.tx_dma_ch].CCR & DMA_CCR_EN) {
|
||||
/* do nothing */
|
||||
}
|
||||
|
||||
if (uart_st.tx_buf.wraparound) {
|
||||
uart_schedule_dma(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* len is the packet length including headers */
|
||||
int uart_send_packet_nonblocking(struct ll_pkt *pkt, size_t pkt_len) {
|
||||
if (uart_st.tx_buf.packet_end[uart_st.tx_buf.wr_idx] != -1) {
|
||||
/* Find a free slot for this packet */
|
||||
uart_st.tx_overruns++;
|
||||
return ERR_BUSY;
|
||||
}
|
||||
|
||||
/* make the value this wonky-ass CRC implementation produces match zlib etc. */
|
||||
CRC->CR = CRC_CR_REV_OUT | (1<<CRC_CR_REV_IN_Pos) | CRC_CR_RESET;
|
||||
for (size_t i=offsetof(struct ll_pkt, pid); i<pkt_len; i++)
|
||||
CRC->DR = ((uint8_t *)pkt)[i];
|
||||
pkt->crc32 = ~CRC->DR;
|
||||
|
||||
int rc = cobs_encode_usart((int (*)(char))uart_putc_nonblocking, (char *)pkt, pkt_len);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
uart_st.tx_buf.packet_end[uart_st.tx_buf.wr_idx] = uart_st.tx_buf.wr_pos;
|
||||
uart_st.tx_buf.wr_idx = (uart_st.tx_buf.wr_idx + 1) % COUNT_OF(uart_st.tx_buf.packet_end);
|
||||
|
||||
uart_st.packet_count++;
|
||||
|
||||
if (!(DMA1_Channel[uart_st.tx_dma_ch].CCR & DMA_CCR_EN))
|
||||
uart_schedule_dma(false);
|
||||
return 0;
|
||||
}
|
||||
|
||||
100
src/usb_if.c
100
src/usb_if.c
|
|
@ -1,14 +1,11 @@
|
|||
|
||||
#include <global.h>
|
||||
#include <usb_if.h>
|
||||
#include <usb.h>
|
||||
#include <usb_cdc.h>
|
||||
|
||||
|
||||
#define USB_EP0_SIZE 8
|
||||
#define USB_CDC_RX_EP 0x01
|
||||
#define USB_CDC_TX_EP 0x81
|
||||
#define USB_CDC_DATA_SIZE 0x40
|
||||
#define USB_CDC_NTF_EP 0x82
|
||||
#define USB_CDC_NTF_SIZE 0x08
|
||||
|
||||
|
|
@ -145,17 +142,7 @@ static const struct usb_string_descriptor lang_desc = USB_ARRAY_DESC(USB_LAN
|
|||
static const struct usb_string_descriptor manuf_desc_en = USB_STRING_DESC("TU Darmstadt, KOM / emergenCITY");
|
||||
static const struct usb_string_descriptor prod_desc_en = USB_STRING_DESC("IHSM rotor tester");
|
||||
|
||||
static struct usb_cdc_line_coding cdc_line = {
|
||||
.dwDTERate = 115200,
|
||||
.bCharFormat = USB_CDC_1_STOP_BITS,
|
||||
.bParityType = USB_CDC_NO_PARITY,
|
||||
.bDataBits = 8,
|
||||
};
|
||||
|
||||
usbd_device usb_dev;
|
||||
uint32_t usb_buf[0x20];
|
||||
uint8_t fifo[0x200];
|
||||
uint32_t fpos = 0;
|
||||
struct usb_state st_usb;
|
||||
|
||||
static usbd_respond usb_getdesc (usbd_ctlreq *req, void **address, uint16_t *length) {
|
||||
const uint8_t dtype = req->wValue >> 8;
|
||||
|
|
@ -182,13 +169,16 @@ static usbd_respond usb_control(usbd_device *dev, usbd_ctlreq *req, usbd_rqc_cal
|
|||
switch (req->bRequest) {
|
||||
case USB_CDC_SET_CONTROL_LINE_STATE:
|
||||
return usbd_ack;
|
||||
|
||||
case USB_CDC_SET_LINE_CODING:
|
||||
memcpy(&cdc_line, req->data, sizeof(cdc_line));
|
||||
memcpy(&st_usb.line, req->data, sizeof(st_usb.line));
|
||||
return usbd_ack;
|
||||
|
||||
case USB_CDC_GET_LINE_CODING:
|
||||
dev->status.data_ptr = &cdc_line;
|
||||
dev->status.data_count = sizeof(cdc_line);
|
||||
dev->status.data_ptr = &st_usb.line;
|
||||
dev->status.data_count = sizeof(st_usb.line);
|
||||
return usbd_ack;
|
||||
|
||||
default:
|
||||
return usbd_fail;
|
||||
}
|
||||
|
|
@ -197,21 +187,42 @@ static usbd_respond usb_control(usbd_device *dev, usbd_ctlreq *req, usbd_rqc_cal
|
|||
return usbd_fail;
|
||||
}
|
||||
|
||||
static void usb_loopback(usbd_device *dev, uint8_t event, uint8_t ep) {
|
||||
int _t;
|
||||
if (fpos <= (sizeof(fifo) - USB_CDC_DATA_SIZE)) {
|
||||
_t = usbd_ep_read(dev, USB_CDC_RX_EP, &fifo[fpos], USB_CDC_DATA_SIZE);
|
||||
if (_t > 0) {
|
||||
fpos += _t;
|
||||
static void usb_cobs_rx(usbd_device *dev, uint8_t event, uint8_t ep) {
|
||||
uint8_t buf[USB_CDC_DATA_SIZE];
|
||||
int nread = usbd_ep_read(dev, USB_CDC_RX_EP, buf, USB_CDC_DATA_SIZE);
|
||||
for (int i=0; i<nread; i++) {
|
||||
int rc = cobs_decode_incremental(&st_usb.cobs_state, (char*)st_usb.usb_pkbuf, sizeof(st_usb.usb_pkbuf), buf[i]);
|
||||
if (rc < 0) { /* Framing error */
|
||||
st_usb.error = ERR_PROTOCOL;
|
||||
st_usb.cobs_synchronized = false;
|
||||
|
||||
} else if (rc > 0 && st_usb.cobs_synchronized) { /* Packet complete */
|
||||
handle_usb_packet(st_usb.usb_pkbuf, rc);
|
||||
|
||||
} /* else rc == 0 -> packet in progress */
|
||||
|
||||
if (buf[i] == 0) {
|
||||
st_usb.cobs_synchronized = true;
|
||||
}
|
||||
}
|
||||
if (fpos > 0) {
|
||||
_t = usbd_ep_write(dev, USB_CDC_TX_EP, &fifo[0], (fpos < USB_CDC_DATA_SIZE) ? fpos : USB_CDC_DATA_SIZE);
|
||||
if (_t > 0) {
|
||||
memmove(&fifo[0], &fifo[_t], fpos - _t);
|
||||
fpos -= _t;
|
||||
}
|
||||
}
|
||||
|
||||
static int usb_cobs_output(char c) {
|
||||
if (st_usb.txpos == sizeof(st_usb.txbuf)) {
|
||||
return ERR_BUFFER_OVERFLOW;
|
||||
}
|
||||
|
||||
st_usb.txbuf[st_usb.txpos++] = c;
|
||||
return ERR_SUCCESS;
|
||||
}
|
||||
|
||||
ErrorCode usb_write_response(void *data, size_t len) {
|
||||
st_usb.txpos = 0;
|
||||
return cobs_encode_usart(usb_cobs_output, data, len);
|
||||
}
|
||||
|
||||
static void usb_cobs_tx(usbd_device *dev, uint8_t event, uint8_t ep) {
|
||||
/* do nothing, we enqueue packets manually in usb_write_response. */
|
||||
}
|
||||
|
||||
static usbd_respond usb_setconf (usbd_device *dev, uint8_t cfg) {
|
||||
|
|
@ -224,32 +235,45 @@ static usbd_respond usb_setconf (usbd_device *dev, uint8_t cfg) {
|
|||
usbd_reg_endpoint(dev, USB_CDC_RX_EP, 0);
|
||||
usbd_reg_endpoint(dev, USB_CDC_TX_EP, 0);
|
||||
return usbd_ack;
|
||||
|
||||
case 1:
|
||||
/* configuring device */
|
||||
usbd_ep_config(dev, USB_CDC_RX_EP, USB_EPTYPE_BULK /*| USB_EPTYPE_DBLBUF*/, USB_CDC_DATA_SIZE);
|
||||
usbd_ep_config(dev, USB_CDC_TX_EP, USB_EPTYPE_BULK /*| USB_EPTYPE_DBLBUF*/, USB_CDC_DATA_SIZE);
|
||||
usbd_ep_config(dev, USB_CDC_NTF_EP, USB_EPTYPE_INTERRUPT, USB_CDC_NTF_SIZE);
|
||||
usbd_reg_endpoint(dev, USB_CDC_RX_EP, usb_loopback);
|
||||
usbd_reg_endpoint(dev, USB_CDC_TX_EP, usb_loopback);
|
||||
usbd_reg_endpoint(dev, USB_CDC_RX_EP, usb_cobs_tx);
|
||||
usbd_reg_endpoint(dev, USB_CDC_TX_EP, usb_cobs_rx);
|
||||
usbd_ep_write(dev, USB_CDC_TX_EP, 0, 0);
|
||||
|
||||
cobs_decode_incremental_initialize(&st_usb.cobs_state);
|
||||
st_usb.cobs_synchronized = false;
|
||||
|
||||
st_usb.line.dwDTERate = 115200;
|
||||
st_usb.line.bCharFormat = USB_CDC_1_STOP_BITS;
|
||||
st_usb.line.bParityType = USB_CDC_NO_PARITY;
|
||||
st_usb.line.bDataBits = 8;
|
||||
|
||||
st_usb.error = ERR_SUCCESS;
|
||||
|
||||
return usbd_ack;
|
||||
|
||||
default:
|
||||
return usbd_fail;
|
||||
}
|
||||
}
|
||||
|
||||
void usb_init() {
|
||||
usbd_init(&usb_dev, &usbd_hw, USB_EP0_SIZE, usb_buf, sizeof(usb_buf));
|
||||
usbd_reg_config(&usb_dev, usb_setconf);
|
||||
usbd_reg_control(&usb_dev, usb_control);
|
||||
usbd_reg_descr(&usb_dev, usb_getdesc);
|
||||
usbd_enable(&usb_dev, true);
|
||||
usbd_connect(&usb_dev, true);
|
||||
usbd_init(&st_usb.usb_dev, &usbd_hw, USB_EP0_SIZE, st_usb.usb_buf, sizeof(st_usb.usb_buf));
|
||||
usbd_reg_config(&st_usb.usb_dev, usb_setconf);
|
||||
usbd_reg_control(&st_usb.usb_dev, usb_control);
|
||||
usbd_reg_descr(&st_usb.usb_dev, usb_getdesc);
|
||||
usbd_enable(&st_usb.usb_dev, true);
|
||||
usbd_connect(&st_usb.usb_dev, true);
|
||||
NVIC_EnableIRQ(USB_IRQn);
|
||||
}
|
||||
|
||||
void USB_IRQHandler() {
|
||||
usbd_poll(&usb_dev);
|
||||
usbd_poll(&st_usb.usb_dev);
|
||||
USB->ISTR = 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue