Martin Mareš
2 months ago
1 changed files with 585 additions and 0 deletions
@ -0,0 +1,585 @@ |
|||||
|
/*
|
||||
|
* USB-RS485 Switch -- Hardware Testing |
||||
|
* |
||||
|
* (c) 2022 Martin Mareš <mj@ucw.cz> |
||||
|
*/ |
||||
|
|
||||
|
#include "util.h" |
||||
|
|
||||
|
#include <libopencm3/cm3/cortex.h> |
||||
|
#include <libopencm3/cm3/nvic.h> |
||||
|
#include <libopencm3/cm3/systick.h> |
||||
|
#include <libopencm3/cm3/scb.h> |
||||
|
#include <libopencm3/stm32/adc.h> |
||||
|
#include <libopencm3/stm32/gpio.h> |
||||
|
#include <libopencm3/stm32/rcc.h> |
||||
|
#include <libopencm3/stm32/spi.h> |
||||
|
#include <libopencm3/stm32/timer.h> |
||||
|
#include <libopencm3/stm32/usart.h> |
||||
|
#include <libopencm3/usb/dfu.h> |
||||
|
#include <libopencm3/usb/usbd.h> |
||||
|
|
||||
|
#include <string.h> |
||||
|
|
||||
|
/*** Hardware init ***/ |
||||
|
|
||||
|
static void clock_init(void) |
||||
|
{ |
||||
|
rcc_clock_setup_pll(&rcc_hse_configs[RCC_CLOCK_HSE8_72MHZ]); |
||||
|
|
||||
|
rcc_periph_clock_enable(RCC_GPIOA); |
||||
|
rcc_periph_clock_enable(RCC_GPIOB); |
||||
|
rcc_periph_clock_enable(RCC_GPIOC); |
||||
|
rcc_periph_clock_enable(RCC_USART1); |
||||
|
rcc_periph_clock_enable(RCC_USART2); |
||||
|
rcc_periph_clock_enable(RCC_USART3); |
||||
|
rcc_periph_clock_enable(RCC_SPI2); |
||||
|
// rcc_periph_clock_enable(RCC_TIM4);
|
||||
|
rcc_periph_clock_enable(RCC_ADC1); |
||||
|
rcc_periph_clock_enable(RCC_AFIO); |
||||
|
|
||||
|
rcc_periph_reset_pulse(RST_GPIOA); |
||||
|
rcc_periph_reset_pulse(RST_GPIOB); |
||||
|
rcc_periph_reset_pulse(RST_GPIOC); |
||||
|
rcc_periph_reset_pulse(RST_USART1); |
||||
|
rcc_periph_reset_pulse(RST_USART2); |
||||
|
rcc_periph_reset_pulse(RST_USART3); |
||||
|
rcc_periph_reset_pulse(RST_SPI2); |
||||
|
// rcc_periph_reset_pulse(RST_TIM4);
|
||||
|
rcc_periph_reset_pulse(RST_ADC1); |
||||
|
rcc_periph_reset_pulse(RST_AFIO); |
||||
|
} |
||||
|
|
||||
|
static void gpio_init(void) |
||||
|
{ |
||||
|
// PA0 = VCC sense -> ADC12_IN0
|
||||
|
// PA1 = 5V sense -> ADC12_IN1
|
||||
|
// PA2 = TXD2 (debug)
|
||||
|
// PA3 = RXD2
|
||||
|
// PA4 = SPI1_SS* (jumpers)
|
||||
|
// PA5 = SPI1_SCK
|
||||
|
// PA6 = SPI1_MISO
|
||||
|
// PA7 = SPI1_MOSI
|
||||
|
// PA8 = SPI2_OE*
|
||||
|
// PA9 = TXD1
|
||||
|
// PA10 = RXD1
|
||||
|
// PA11 = USB_DN
|
||||
|
// PA12 = USB_DP
|
||||
|
// PA13 + PA14 = programming interface
|
||||
|
// PA15 = GPIO3
|
||||
|
|
||||
|
// PB0 = GPIO0 = ADuM4160 PIN (USB upstream enable)
|
||||
|
// PB1 = I_SENSE -> ADC12_IN9
|
||||
|
// PB2 = unused
|
||||
|
// PB3 = I_SEN_A
|
||||
|
// PB4 = I_SEN_B
|
||||
|
// PB5 = I_SEN_C
|
||||
|
// PB6 = I2C1_SCL
|
||||
|
// PB7 = I2C1_SDA
|
||||
|
// PB8 = GPIO1
|
||||
|
// PB9 = GPIO2
|
||||
|
// PB10 = TXD3
|
||||
|
// PB11 = RXD3
|
||||
|
// PB12 = SPI2_STROBE
|
||||
|
// PB13 = SPI2_SCK
|
||||
|
// PB14 = SPI2_MISO
|
||||
|
// PB15 = SPI2_MOSI
|
||||
|
|
||||
|
// PC13 = debugging LED *
|
||||
|
// PC14 = unused
|
||||
|
// PC15 = unused
|
||||
|
|
||||
|
// Switch JTAG off to free up pins
|
||||
|
gpio_primary_remap(AFIO_MAPR_SWJ_CFG_JTAG_OFF_SW_ON, 0); |
||||
|
} |
||||
|
|
||||
|
static void debug_init(void) |
||||
|
{ |
||||
|
// PC13 = debugging LED à la BluePill
|
||||
|
gpio_set_mode(GPIOC, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, GPIO13); |
||||
|
gpio_clear(GPIOC, GPIO13); |
||||
|
|
||||
|
// USART2: Debugging console
|
||||
|
// PA2 = TXD2
|
||||
|
// PA3 = RXD2
|
||||
|
gpio_set_mode(GPIOA, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, GPIO2); |
||||
|
gpio_set_mode(GPIOA, GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, GPIO3); |
||||
|
|
||||
|
usart_set_baudrate(USART2, 115200); |
||||
|
usart_set_databits(USART2, 8); |
||||
|
usart_set_stopbits(USART2, USART_STOPBITS_1); |
||||
|
usart_set_mode(USART2, USART_MODE_TX_RX); |
||||
|
usart_set_parity(USART2, USART_PARITY_NONE); |
||||
|
usart_set_flow_control(USART2, USART_FLOWCONTROL_NONE); |
||||
|
|
||||
|
usart_enable(USART2); |
||||
|
} |
||||
|
|
||||
|
/*** System ticks ***/ |
||||
|
|
||||
|
static volatile u32 ms_ticks; |
||||
|
|
||||
|
void sys_tick_handler(void) |
||||
|
{ |
||||
|
ms_ticks++; |
||||
|
} |
||||
|
|
||||
|
static void tick_init(void) |
||||
|
{ |
||||
|
systick_set_frequency(1000, CPU_CLOCK_MHZ * 1000000); |
||||
|
systick_counter_enable(); |
||||
|
systick_interrupt_enable(); |
||||
|
} |
||||
|
|
||||
|
static void delay_ms(uint ms) |
||||
|
{ |
||||
|
u32 start_ticks = ms_ticks; |
||||
|
while (ms_ticks - start_ticks < ms) |
||||
|
; |
||||
|
} |
||||
|
|
||||
|
/*** Shift registers ***/ |
||||
|
|
||||
|
static void reg_init(void) |
||||
|
{ |
||||
|
// Pins: PA8=OE*, PB12=STROBE, PB13=SCK, PB14=MISO, PB15=MOSI
|
||||
|
gpio_set_mode(GPIOA, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, GPIO8); |
||||
|
gpio_set_mode(GPIOB, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, GPIO12); |
||||
|
gpio_set_mode(GPIOB, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, GPIO13 | GPIO15); |
||||
|
gpio_set_mode(GPIOB, GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, GPIO14); |
||||
|
|
||||
|
gpio_set(GPIOA, GPIO8); |
||||
|
gpio_clear(GPIOB, GPIO12); |
||||
|
|
||||
|
spi_reset(SPI2); |
||||
|
|
||||
|
/*
|
||||
|
* Set up SPI in Master mode with: |
||||
|
* |
||||
|
* - baud rate: 1/64 of peripheral clock frequency |
||||
|
* - clock polarity: idle high |
||||
|
* - clock phase: data valid on 2nd clock pulse |
||||
|
* - data frame format: 8-bit, MSB first |
||||
|
*/ |
||||
|
spi_init_master(SPI2, SPI_CR1_BAUDRATE_FPCLK_DIV_64, SPI_CR1_CPOL_CLK_TO_1_WHEN_IDLE, |
||||
|
SPI_CR1_CPHA_CLK_TRANSITION_2, SPI_CR1_DFF_8BIT, SPI_CR1_MSBFIRST); |
||||
|
|
||||
|
// NSS will be managed by software and always held high
|
||||
|
spi_enable_software_slave_management(SPI2); |
||||
|
spi_set_nss_high(SPI2); |
||||
|
|
||||
|
spi_enable(SPI2); |
||||
|
} |
||||
|
|
||||
|
static byte reg_state[4] = { 0x88, 0x88, 0x88, 0x88 }; |
||||
|
|
||||
|
static void reg_send(void) |
||||
|
{ |
||||
|
for (byte i=0; i<4; i++) |
||||
|
spi_send(SPI2, reg_state[3-i]); |
||||
|
while (SPI_SR(SPI2) & SPI_SR_BSY) |
||||
|
; |
||||
|
gpio_set(GPIOB, GPIO12); // strobe
|
||||
|
asm volatile ("nop; nop; nop; nop"); // just to be sure
|
||||
|
gpio_clear(GPIOB, GPIO12); |
||||
|
gpio_clear(GPIOA, GPIO8); // OE*
|
||||
|
} |
||||
|
|
||||
|
enum reg_flags { |
||||
|
SF_RXEN_N = 8, |
||||
|
SF_TXEN = 4, |
||||
|
SF_PWREN = 2, |
||||
|
SF_LED = 1, |
||||
|
}; |
||||
|
|
||||
|
static void reg_set_flag(uint port, uint flag) |
||||
|
{ |
||||
|
reg_state[port/2] |= (port & 1) ? flag : (flag << 4); |
||||
|
} |
||||
|
|
||||
|
static void reg_clear_flag(uint port, uint flag) |
||||
|
{ |
||||
|
reg_state[port/2] &= ~((port & 1) ? flag : (flag << 4)); |
||||
|
} |
||||
|
|
||||
|
static void reg_toggle_flag(uint port, uint flag) |
||||
|
{ |
||||
|
reg_state[port/2] ^= (port & 1) ? flag : (flag << 4); |
||||
|
} |
||||
|
|
||||
|
/*** ADC ***/ |
||||
|
|
||||
|
static void adc_init(void) |
||||
|
{ |
||||
|
// PA0, PA1 and PB1 are analog inputs
|
||||
|
gpio_set_mode(GPIOA, GPIO_MODE_INPUT, GPIO_CNF_INPUT_ANALOG, GPIO0 | GPIO1); |
||||
|
gpio_set_mode(GPIOB, GPIO_MODE_INPUT, GPIO_CNF_INPUT_ANALOG, GPIO1); |
||||
|
|
||||
|
// PB3 to PB5 control the analog multiplexer on PB1
|
||||
|
gpio_set_mode(GPIOB, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, GPIO3 | GPIO4 | GPIO5); |
||||
|
|
||||
|
adc_power_off(ADC1); |
||||
|
// ADC prescaler set by rcc_clock_setup_pll(): ADC clock = PCLK2/8 = 9 MHz
|
||||
|
rcc_set_adcpre(RCC_CFGR_ADCPRE_PCLK2_DIV8); |
||||
|
adc_disable_scan_mode(ADC1); |
||||
|
adc_set_single_conversion_mode(ADC1); |
||||
|
adc_set_sample_time(ADC1, ADC_CHANNEL0, ADC_SMPR_SMP_239DOT5CYC); |
||||
|
adc_set_sample_time(ADC1, ADC_CHANNEL1, ADC_SMPR_SMP_239DOT5CYC); |
||||
|
adc_set_sample_time(ADC1, ADC_CHANNEL9, ADC_SMPR_SMP_239DOT5CYC); |
||||
|
adc_set_sample_time(ADC1, ADC_CHANNEL16, ADC_SMPR_SMP_239DOT5CYC); |
||||
|
adc_set_sample_time(ADC1, ADC_CHANNEL17, ADC_SMPR_SMP_239DOT5CYC); |
||||
|
adc_enable_external_trigger_regular(ADC1, ADC_CR2_EXTSEL_SWSTART); |
||||
|
adc_enable_temperature_sensor(); |
||||
|
adc_power_on(ADC1); |
||||
|
adc_reset_calibration(ADC1); |
||||
|
adc_calibrate(ADC1); |
||||
|
} |
||||
|
|
||||
|
static void adc_test(void) |
||||
|
{ |
||||
|
for (int i=0; i<4; i++) { |
||||
|
uint j=0; |
||||
|
switch (i) { |
||||
|
case 0: |
||||
|
j = ADC_CHANNEL0; |
||||
|
break; |
||||
|
case 1: |
||||
|
j = ADC_CHANNEL1; |
||||
|
break; |
||||
|
case 2: |
||||
|
j = ADC_CHANNEL16; |
||||
|
break; |
||||
|
case 3: |
||||
|
j = ADC_CHANNEL17; |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
uint8_t channels[] = { j }; |
||||
|
adc_set_regular_sequence(ADC1, 1, channels); |
||||
|
|
||||
|
adc_start_conversion_regular(ADC1); |
||||
|
|
||||
|
while (! adc_eoc(ADC1)); |
||||
|
uint reg16 = adc_read_regular(ADC1); |
||||
|
debug_printf("ADC %d = %d\n", i, reg16); |
||||
|
} |
||||
|
|
||||
|
for (int i=0; i<8; i++) { |
||||
|
gpio_clear(GPIOB, GPIO3 | GPIO4 | GPIO5); |
||||
|
gpio_set(GPIOB, i << 3); |
||||
|
delay_ms(5); |
||||
|
|
||||
|
uint8_t channels[] = { ADC_CHANNEL9 }; |
||||
|
adc_set_regular_sequence(ADC1, 1, channels); |
||||
|
|
||||
|
adc_start_conversion_regular(ADC1); |
||||
|
|
||||
|
while (! adc_eoc(ADC1)); |
||||
|
uint reg16 = adc_read_regular(ADC1); |
||||
|
debug_printf("SENSE %d = %d\n", i, reg16); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/*** Loopback between ports 1 and 5 ***/ |
||||
|
|
||||
|
static void loop_init(void) |
||||
|
{ |
||||
|
// USART1: Ports 1 to 4
|
||||
|
// PA9 = TXD1
|
||||
|
// PA10 = RXD1
|
||||
|
gpio_set_mode(GPIOA, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, GPIO9); |
||||
|
gpio_set_mode(GPIOA, GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, GPIO10); |
||||
|
|
||||
|
usart_set_baudrate(USART1, 115200); |
||||
|
usart_set_databits(USART1, 8); |
||||
|
usart_set_stopbits(USART1, USART_STOPBITS_1); |
||||
|
usart_set_mode(USART1, USART_MODE_TX_RX); |
||||
|
usart_set_parity(USART1, USART_PARITY_NONE); |
||||
|
usart_set_flow_control(USART1, USART_FLOWCONTROL_NONE); |
||||
|
|
||||
|
usart_enable(USART1); |
||||
|
|
||||
|
// USART3: Ports 5 to 9
|
||||
|
// PB10 = TXD3
|
||||
|
// PB11 = RXD3
|
||||
|
gpio_set_mode(GPIOB, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, GPIO10); |
||||
|
gpio_set_mode(GPIOB, GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, 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); |
||||
|
|
||||
|
// Enable TX on port 1
|
||||
|
reg_set_flag(0, SF_TXEN); |
||||
|
|
||||
|
// Enable RX on port 5
|
||||
|
reg_clear_flag(4, SF_RXEN_N); |
||||
|
} |
||||
|
|
||||
|
static void loop_recv(void) |
||||
|
{ |
||||
|
if (usart_get_flag(USART3, USART_SR_RXNE)) { |
||||
|
uint ch = usart_recv(USART3); |
||||
|
debug_putc(ch); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
static void loop_send(uint ch) |
||||
|
{ |
||||
|
usart_send_blocking(USART1, ch); |
||||
|
} |
||||
|
|
||||
|
/*** USB ***/ |
||||
|
|
||||
|
#define USB_RS485_USB_VENDOR 0x4242 |
||||
|
#define USB_RS485_USB_PRODUCT 0x000b |
||||
|
#define USB_RS485_USB_VERSION 1 |
||||
|
|
||||
|
static usbd_device *usbd_dev; |
||||
|
|
||||
|
enum usb_string { |
||||
|
STR_MANUFACTURER = 1, |
||||
|
STR_PRODUCT, |
||||
|
STR_SERIAL, |
||||
|
}; |
||||
|
|
||||
|
static char usb_serial_number[13]; |
||||
|
|
||||
|
static const char *usb_strings[] = { |
||||
|
"United Computer Wizards", |
||||
|
"USB-RS485 Switch", |
||||
|
usb_serial_number, |
||||
|
}; |
||||
|
|
||||
|
static const struct usb_device_descriptor device = { |
||||
|
.bLength = USB_DT_DEVICE_SIZE, |
||||
|
.bDescriptorType = USB_DT_DEVICE, |
||||
|
.bcdUSB = 0x0200, |
||||
|
.bDeviceClass = 0xFF, |
||||
|
.bDeviceSubClass = 0, |
||||
|
.bDeviceProtocol = 0, |
||||
|
.bMaxPacketSize0 = 64, |
||||
|
.idVendor = USB_RS485_USB_VENDOR, |
||||
|
.idProduct = USB_RS485_USB_PRODUCT, |
||||
|
.bcdDevice = USB_RS485_USB_VERSION, |
||||
|
.iManufacturer = STR_MANUFACTURER, |
||||
|
.iProduct = STR_PRODUCT, |
||||
|
.iSerialNumber = STR_SERIAL, |
||||
|
.bNumConfigurations = 1, |
||||
|
}; |
||||
|
|
||||
|
static const struct usb_endpoint_descriptor endpoints[] = {{ |
||||
|
// Bulk end-point for sending LED values
|
||||
|
.bLength = USB_DT_ENDPOINT_SIZE, |
||||
|
.bDescriptorType = USB_DT_ENDPOINT, |
||||
|
.bEndpointAddress = 0x01, |
||||
|
.bmAttributes = USB_ENDPOINT_ATTR_BULK, |
||||
|
.wMaxPacketSize = 64, |
||||
|
.bInterval = 1, |
||||
|
}}; |
||||
|
|
||||
|
static const struct usb_interface_descriptor iface = { |
||||
|
.bLength = USB_DT_INTERFACE_SIZE, |
||||
|
.bDescriptorType = USB_DT_INTERFACE, |
||||
|
.bInterfaceNumber = 0, |
||||
|
.bAlternateSetting = 0, |
||||
|
.bNumEndpoints = 1, |
||||
|
.bInterfaceClass = 0xFF, |
||||
|
.bInterfaceSubClass = 0, |
||||
|
.bInterfaceProtocol = 0, |
||||
|
.iInterface = 0, |
||||
|
.endpoint = endpoints, |
||||
|
}; |
||||
|
|
||||
|
static const struct usb_dfu_descriptor dfu_function = { |
||||
|
.bLength = sizeof(struct usb_dfu_descriptor), |
||||
|
.bDescriptorType = DFU_FUNCTIONAL, |
||||
|
.bmAttributes = USB_DFU_CAN_DOWNLOAD | USB_DFU_WILL_DETACH, |
||||
|
.wDetachTimeout = 255, |
||||
|
.wTransferSize = 1024, |
||||
|
.bcdDFUVersion = 0x0100, |
||||
|
}; |
||||
|
|
||||
|
static const struct usb_interface_descriptor dfu_iface = { |
||||
|
.bLength = USB_DT_INTERFACE_SIZE, |
||||
|
.bDescriptorType = USB_DT_INTERFACE, |
||||
|
.bInterfaceNumber = 1, |
||||
|
.bAlternateSetting = 0, |
||||
|
.bNumEndpoints = 0, |
||||
|
.bInterfaceClass = 0xFE, |
||||
|
.bInterfaceSubClass = 1, |
||||
|
.bInterfaceProtocol = 1, |
||||
|
.iInterface = 0, |
||||
|
|
||||
|
.extra = &dfu_function, |
||||
|
.extralen = sizeof(dfu_function), |
||||
|
}; |
||||
|
|
||||
|
static const struct usb_interface ifaces[] = {{ |
||||
|
.num_altsetting = 1, |
||||
|
.altsetting = &iface, |
||||
|
}, { |
||||
|
.num_altsetting = 1, |
||||
|
.altsetting = &dfu_iface, |
||||
|
}}; |
||||
|
|
||||
|
static const struct usb_config_descriptor config = { |
||||
|
.bLength = USB_DT_CONFIGURATION_SIZE, |
||||
|
.bDescriptorType = USB_DT_CONFIGURATION, |
||||
|
.wTotalLength = 0, |
||||
|
.bNumInterfaces = 2, |
||||
|
.bConfigurationValue = 1, |
||||
|
.iConfiguration = 0, |
||||
|
.bmAttributes = 0x80, |
||||
|
.bMaxPower = 100, // multiplied by 2 mA
|
||||
|
.interface = ifaces, |
||||
|
}; |
||||
|
|
||||
|
static byte usb_configured; |
||||
|
static uint8_t usbd_control_buffer[64]; |
||||
|
|
||||
|
static void dfu_detach_complete(usbd_device *dev UNUSED, struct usb_setup_data *req UNUSED) |
||||
|
{ |
||||
|
// Reset to bootloader, which implements the rest of DFU
|
||||
|
debug_printf("Switching to DFU\n"); |
||||
|
debug_flush(); |
||||
|
scb_reset_core(); |
||||
|
} |
||||
|
|
||||
|
static enum usbd_request_return_codes dfu_control_cb(usbd_device *dev UNUSED, |
||||
|
struct usb_setup_data *req, |
||||
|
uint8_t **buf UNUSED, |
||||
|
uint16_t *len UNUSED, |
||||
|
void (**complete)(usbd_device *dev, struct usb_setup_data *req)) |
||||
|
{ |
||||
|
if (req->bmRequestType != 0x21 || req->bRequest != DFU_DETACH) |
||||
|
return USBD_REQ_NOTSUPP; |
||||
|
|
||||
|
*complete = dfu_detach_complete; |
||||
|
return USBD_REQ_HANDLED; |
||||
|
} |
||||
|
|
||||
|
static byte usb_rx_buf[64]; |
||||
|
|
||||
|
static void ep01_cb(usbd_device *dev, uint8_t ep UNUSED) |
||||
|
{ |
||||
|
// We received a frame from the USB host
|
||||
|
uint len = usbd_ep_read_packet(dev, 0x01, usb_rx_buf, sizeof(usb_rx_buf)); |
||||
|
debug_printf("USB: Host sent %u bytes\n", len); |
||||
|
} |
||||
|
|
||||
|
static void set_config_cb(usbd_device *dev, uint16_t wValue UNUSED) |
||||
|
{ |
||||
|
usbd_register_control_callback( |
||||
|
dev, |
||||
|
USB_REQ_TYPE_CLASS | USB_REQ_TYPE_INTERFACE, |
||||
|
USB_REQ_TYPE_TYPE | USB_REQ_TYPE_RECIPIENT, |
||||
|
dfu_control_cb); |
||||
|
usbd_ep_setup(dev, 0x01, USB_ENDPOINT_ATTR_BULK, 64, ep01_cb); |
||||
|
usb_configured = 1; |
||||
|
} |
||||
|
|
||||
|
static void reset_cb(void) |
||||
|
{ |
||||
|
debug_printf("USB: Reset\n"); |
||||
|
usb_configured = 0; |
||||
|
} |
||||
|
|
||||
|
static volatile bool usb_event_pending; |
||||
|
|
||||
|
void usb_lp_can_rx0_isr(void) |
||||
|
{ |
||||
|
/*
|
||||
|
* We handle USB in the main loop to avoid race conditions between |
||||
|
* USB interrupts and other code. However, we need an interrupt to |
||||
|
* up the main loop from sleep. |
||||
|
* |
||||
|
* We set up only the low-priority ISR, because high-priority ISR handles |
||||
|
* only double-buffered bulk transfers and isochronous transfers. |
||||
|
*/ |
||||
|
nvic_disable_irq(NVIC_USB_LP_CAN_RX0_IRQ); |
||||
|
usb_event_pending = 1; |
||||
|
} |
||||
|
|
||||
|
static void usb_init(void) |
||||
|
{ |
||||
|
// Simulate USB disconnect
|
||||
|
gpio_set_mode(GPIOB, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, GPIO0); |
||||
|
gpio_clear(GPIOB, GPIO0); |
||||
|
delay_ms(100); |
||||
|
gpio_set(GPIOB, GPIO0); |
||||
|
|
||||
|
usbd_dev = usbd_init( |
||||
|
&st_usbfs_v1_usb_driver, |
||||
|
&device, |
||||
|
&config, |
||||
|
usb_strings, |
||||
|
ARRAY_SIZE(usb_strings), |
||||
|
usbd_control_buffer, |
||||
|
sizeof(usbd_control_buffer) |
||||
|
); |
||||
|
usbd_register_reset_callback(usbd_dev, reset_cb); |
||||
|
usbd_register_set_config_callback(usbd_dev, set_config_cb); |
||||
|
usb_event_pending = 1; |
||||
|
} |
||||
|
|
||||
|
/*** Main ***/ |
||||
|
|
||||
|
int main(void) |
||||
|
{ |
||||
|
clock_init(); |
||||
|
gpio_init(); |
||||
|
debug_init(); |
||||
|
reg_init(); |
||||
|
tick_init(); |
||||
|
adc_init(); |
||||
|
usb_init(); |
||||
|
loop_init(); |
||||
|
|
||||
|
debug_printf("Lisak je lisak...\n"); |
||||
|
|
||||
|
byte t = 0; |
||||
|
u32 last_blink = 0; |
||||
|
|
||||
|
for (;;) { |
||||
|
if (ms_ticks - last_blink >= 250) { |
||||
|
debug_led_toggle(); |
||||
|
reg_clear_flag(t, SF_LED); |
||||
|
t = (t+1) & 7; |
||||
|
reg_set_flag(t, SF_LED); |
||||
|
reg_send(); |
||||
|
last_blink = ms_ticks; |
||||
|
} |
||||
|
|
||||
|
if (usart_get_flag(USART2, USART_SR_RXNE)) { |
||||
|
uint ch = usart_recv(USART2); |
||||
|
debug_putc(ch); |
||||
|
if (ch >= '0' && ch <= '7') { |
||||
|
reg_toggle_flag(ch - '0', SF_PWREN); |
||||
|
reg_send(); |
||||
|
} else if (ch == 'a') { |
||||
|
adc_test(); |
||||
|
} else { |
||||
|
loop_send(ch); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
loop_recv(); |
||||
|
|
||||
|
if (usb_event_pending) { |
||||
|
usbd_poll(usbd_dev); |
||||
|
usb_event_pending = 0; |
||||
|
nvic_clear_pending_irq(NVIC_USB_LP_CAN_RX0_IRQ); |
||||
|
nvic_enable_irq(NVIC_USB_LP_CAN_RX0_IRQ); |
||||
|
} |
||||
|
|
||||
|
wait_for_interrupt(); |
||||
|
} |
||||
|
|
||||
|
return 0; |
||||
|
} |
Loading…
Reference in new issue