/* * This is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2, as * published by the Free Software Foundation. * * this software 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 software. If not, see . * * Author: Daniele Lacamera * * */ #include #include #include #include #include #include #include #include #include #include #include #include "system.h" #include "timer.h" #include "cbuf.h" #include "spi_flash.h" #include "spi_drv_stm32f4.h" #define LED2CTL GPIO14 // A #define LED0CTL GPIO13 // A #define LED1CTL GPIO15 // A #define LED3CTL GPIO4 // B #define SECTOR_SIZE 512 #define USART_BUF 128 #define SAMPLES 10 #define SLEEPTIME static uint8_t spi_page_cache[SPI_FLASH_SECTOR_SIZE]; static uint32_t spi_page_address = (uint32_t)-1; static uint16_t spi_in_page_wr_offset = 0; struct cbuf *inbuf[3]; volatile int timer_elapsed = 0; volatile uint32_t tim2_ticks = 0; volatile uint32_t cpu_freq = 168000000; volatile int powersave = 0; static struct usbd_device *usbd_dev = NULL; static void led_setup(void) { rcc_periph_clock_enable(RCC_GPIOA); rcc_periph_clock_enable(RCC_GPIOB); rcc_periph_clock_enable(RCC_GPIOC); /* Wifi switch + 2 leds */ gpio_mode_setup(GPIOA, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO15 | GPIO14 | GPIO13 ); gpio_set_output_options(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_2MHZ, GPIO15 | GPIO14 | GPIO13); gpio_mode_setup(GPIOB, GPIO_MODE_OUTPUT, GPIO_PUPD_PULLDOWN, GPIO4); gpio_set_output_options(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_2MHZ, GPIO4); gpio_clear(GPIOA, GPIO15 | GPIO14 | GPIO13); gpio_clear(GPIOB, GPIO4); gpio_clear(GPIOA, LED0CTL); } enum main_state { ST_IDLE = 0, ST_START, ST_SENSE, ST_FLASH_OK, ST_READ, ST_WRITE }; static enum main_state main_state = ST_IDLE; static const char VID[] = "0001"; static const char PID[] = "0002"; static const char PR[] = "0003"; static void flash_write_block_final(void) { if (spi_page_address == (uint32_t)(-1)) return; asm volatile ("cpsid i"); spi_flash_sector_erase(spi_page_address); spi_flash_write(spi_page_address, spi_page_cache, SPI_FLASH_SECTOR_SIZE); gpio_clear(GPIOA, LED0CTL); spi_in_page_wr_offset = 0; memset(spi_page_cache, 0xFF, SPI_FLASH_SECTOR_SIZE); spi_page_address = (uint32_t)-1; main_state = ST_FLASH_OK; asm volatile ("cpsie i"); } static int flash_read_block(const usbd_msc_backend *backend, uint32_t lba, void *copy_to) { uint8_t *copy_to_byte = copy_to; flash_write_block_final(); asm volatile ("cpsid i"); memset(copy_to, 0, SECTOR_SIZE); if (lba > get_flash_size()) { gpio_set(GPIOA, LED0CTL); return -1; } gpio_set(GPIOA, LED2CTL); spi_flash_read(lba * SECTOR_SIZE, copy_to, SECTOR_SIZE); asm volatile ("cpsie i"); return 0; } static int flash_write_block(const usbd_msc_backend *backend, uint32_t lba, const void *copy_from) { uint32_t page_address; uint32_t offset; if (lba > get_flash_size()) return -1; page_address = (lba >> 3) * SPI_FLASH_SECTOR_SIZE; offset = (lba & 0x07) * SECTOR_SIZE; if (page_address != spi_page_address) { flash_write_block_final(); gpio_set(GPIOA, LED2CTL); spi_flash_read(page_address, spi_page_cache, SPI_FLASH_SECTOR_SIZE); gpio_clear(GPIOA, LED2CTL); gpio_set(GPIOA, LED0CTL); spi_page_address = page_address; spi_in_page_wr_offset = 0; } if (spi_in_page_wr_offset != offset) return 0; memcpy(spi_page_cache + offset, copy_from, SECTOR_SIZE); spi_in_page_wr_offset += SECTOR_SIZE; if (spi_in_page_wr_offset == SPI_FLASH_SECTOR_SIZE) flash_write_block_final(); return 0; } struct usbd_msc_backend flash_backend = { .vendor_id = VID, .product_id = PID, .product_rev = PR, .block_count = 1, .read_block = flash_read_block, .write_block = flash_write_block, }; const usbd_backend *msc_target_usb_driver(void) { return USBD_STM32_OTG_FS; } static const struct usb_string_descriptor string_lang_list = { .bLength = USB_DT_STRING_SIZE(1), .bDescriptorType = USB_DT_STRING, .wData = { USB_LANGID_ENGLISH_UNITED_STATES } }; const struct usb_string_descriptor usb_string_manuf = { .bLength = USB_DT_STRING_SIZE(10), .bDescriptorType = USB_DT_STRING, /* danielinux */ .wData = { 0x0064, 0x0061, 0x006e, 0x0069, 0x0065, 0x006c, 0x0069, 0x006e, 0x0075, 0x0078 } }; static const struct usb_string_descriptor usb_string_name = { .bLength = USB_DT_STRING_SIZE(26), .bDescriptorType = USB_DT_STRING, /* On the fly ROM dump gadget */ .wData = { 0x004f, 0x006e, 0x0020, 0x0074, 0x0068, 0x0065, 0x0020, 0x0066, 0x006c, 0x0079, 0x0020, 0x0052, 0x004f, 0x004d, 0x0020, 0x0064, 0x0075, 0x006d, 0x0070, 0x0020, 0x0067, 0x0061, 0x0064, 0x0067, 0x0065, 0x0074 } }; static const struct usb_string_descriptor usb_serialn = { .bLength = USB_DT_STRING_SIZE(3), .bDescriptorType = USB_DT_STRING, /* 666 */ .wData = { 0x0036, 0x0036, 0x0036 } }; static const struct usb_string_descriptor **string_data[1] = { (const struct usb_string_descriptor *[]) { &usb_string_manuf, &usb_string_name, &usb_serialn } }; static const struct usb_device_descriptor msc_dev_desc= { .bLength = USB_DT_DEVICE_SIZE, .bDescriptorType = USB_DT_DEVICE, .bcdUSB = 0x0110, .bDeviceClass = 0, .bDeviceSubClass = 0, .bDeviceProtocol = 0, .bMaxPacketSize0 = 64, .idVendor = 0x1d50, .idProduct = 0xDAD0, .bcdDevice = 0x0200, .iManufacturer = 1, .iProduct = 2, .iSerialNumber = 3, .bNumConfigurations = 1 }; static const struct __attribute__((packed)) { struct usb_config_descriptor config; struct usb_interface_descriptor msc_iface; struct usb_endpoint_descriptor msc_endp[2]; } msc_config = { .config = { .bLength = USB_DT_CONFIGURATION_SIZE, .bDescriptorType = USB_DT_CONFIGURATION, .wTotalLength = sizeof(msc_config), .bNumInterfaces = 1, .bConfigurationValue = 1, .iConfiguration = 0, .bmAttributes = 0x80, .bMaxPower = 0x32 }, .msc_iface = { .bLength = USB_DT_INTERFACE_SIZE, .bDescriptorType = USB_DT_INTERFACE, .bInterfaceNumber = 0, .bAlternateSetting = 0, .bNumEndpoints = 2, .bInterfaceClass = USB_CLASS_MSC, .bInterfaceSubClass = USB_MSC_SUBCLASS_SCSI, .bInterfaceProtocol = USB_MSC_PROTOCOL_BBB, .iInterface = 0 }, .msc_endp = {{ .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, .bEndpointAddress = 0x01, .bmAttributes = USB_ENDPOINT_ATTR_BULK, .wMaxPacketSize = 64, .bInterval = 0, }, { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, .bEndpointAddress = 0x82, .bmAttributes = USB_ENDPOINT_ATTR_BULK, .wMaxPacketSize = 64, .bInterval = 0, }} }; static usbd_msc *ms; static void msc_ep_set_config(usbd_device *usbd_dev, const struct usb_config_descriptor *cfg) { (void)cfg; usbd_ep_prepare(usbd_dev, 0x01, USBD_EP_BULK, 64, USBD_INTERVAL_NA, USBD_EP_DOUBLE_BUFFER); usbd_ep_prepare(usbd_dev, 0x82, USBD_EP_BULK, 64, USBD_INTERVAL_NA, USBD_EP_DOUBLE_BUFFER); usbd_msc_start(ms); } static const struct usbd_info_string msc_string = { .lang_list = &string_lang_list, .count = 3, .data = string_data }; static const struct usbd_info msc_info = { .device = { .desc = &msc_dev_desc, .string = &msc_string }, .config = {{ .desc = (const struct usb_config_descriptor *) &msc_config, .string = &msc_string }} }; static void setup_callback(usbd_device *usbd_dev, uint8_t ep_addr, const struct usb_setup_data *setup_data) { (void) ep_addr; /* assuming ep_addr == 0 */ if (!usbd_msc_setup_ep0(ms, setup_data)) { usbd_ep0_setup(usbd_dev, setup_data); } } void usb_fs_init(void) { rcc_periph_clock_enable(RCC_GPIOA); rcc_periph_clock_enable(RCC_OTGFS); gpio_mode_setup(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO9 | GPIO11 | GPIO12); gpio_set_af(GPIOA, GPIO_AF10, GPIO9 | GPIO11 | GPIO12); nvic_enable_irq(NVIC_OTG_FS_IRQ); } void main(void) { uint32_t timeout_counter = 0; uint32_t sense_counter = 0; uint8_t sensor_rawdata[USART_BUF]; int sensor_rawdata_size = 0; int n; uint8_t byte; rcc_clock_setup_hse_3v3(&rcc_hse_12mhz_3v3[RCC_CLOCK_3V3_168MHZ]); led_setup(); timer_init(cpu_freq, 1, 800); while(1) { switch(main_state) { case ST_IDLE: { } break; case ST_START: { uint8_t manuf; spi_flash_probe(); manuf = get_flash_manuf(); if (manuf == 0xBF || manuf == 0xEF) { gpio_clear(GPIOA, LED0CTL); gpio_set(GPIOA, LED2CTL); gpio_set(GPIOB, LED2CTL); main_state = ST_SENSE; } else { gpio_set(GPIOA, LED0CTL); gpio_clear(GPIOA, LED2CTL); gpio_clear(GPIOB, LED3CTL); main_state = ST_IDLE; } } break; case ST_SENSE: { usb_fs_init(); flash_backend.block_count = get_flash_size(); usbd_dev = usbd_init(msc_target_usb_driver(), NULL, &msc_info); ms = usbd_msc_init(usbd_dev, 0x82, 64, 0x01, 64, &flash_backend); usbd_register_set_config_callback(usbd_dev, msc_ep_set_config); usbd_register_setup_callback(usbd_dev, setup_callback); gpio_clear(GPIOA, LED0CTL); gpio_clear(GPIOA, LED2CTL); gpio_set(GPIOB, LED2CTL); main_state = ST_FLASH_OK; } break; case ST_FLASH_OK: case ST_READ: case ST_WRITE: break; } if (usbd_dev) { usbd_poll(usbd_dev, 0); } WFI(); } } #define TIM2_SR (*(volatile uint32_t *)(TIM2_BASE + 0x10)) #define TIM_SR_UIF (1 << 0) void isr_tim2(void) { TIM2_SR &= ~TIM_SR_UIF; tim2_ticks++; timer_elapsed++; if (main_state == ST_IDLE) { gpio_clear(GPIOA, LED1CTL); gpio_set(GPIOA, LED2CTL); // G gpio_clear(GPIOA, LED0CTL); gpio_toggle(GPIOB, LED3CTL); main_state = ST_START; } else if (main_state == ST_START) { gpio_clear(GPIOA, LED1CTL); gpio_clear(GPIOA, LED2CTL); gpio_clear(GPIOA, LED0CTL); gpio_toggle(GPIOB, LED3CTL); } else { gpio_clear(GPIOA, LED1CTL); gpio_clear(GPIOA, LED2CTL); gpio_clear(GPIOA, LED0CTL); gpio_set(GPIOB, LED3CTL); } } void isr_usart1(void) { char c; gpio_toggle(GPIOA, LED0CTL); if (cbuf_bytesfree(inbuf[0]) == 0) { c = usart_recv(USART1); usart_send(USART1, c); return; } if (usart_is_recv_ready(USART1)) { c = usart_recv(USART1); usart_send(USART1, c); cbuf_writebyte(inbuf[0], c); } nvic_clear_pending_irq(NVIC_USART1_IRQ); } void isr_usart2(void) { nvic_clear_pending_irq(NVIC_USART2_IRQ); gpio_toggle(GPIOA, LED0CTL); if (cbuf_bytesfree(inbuf[1]) == 0) { usart_recv(USART2); return; } if (usart_is_recv_ready(USART2)) cbuf_writebyte(inbuf[1], (uint8_t)usart_recv(USART2)); } void isr_usart6(void) { char c; nvic_clear_pending_irq(NVIC_USART6_IRQ); gpio_toggle(GPIOA, LED0CTL); if (cbuf_bytesfree(inbuf[2]) == 0) { c = usart_recv(USART6); return; } if (usart_is_recv_ready(USART6)) { c = usart_recv(USART6); cbuf_writebyte(inbuf[2], c); } } int _write(void *r, uint8_t *text, int len) { char *p = (char *)text; int i = 0; volatile uint32_t reg; while(*p && (i < len)) { usart_send_blocking(USART1, *(p++)); i++; } return len; } void otg_fs_isr(void) { if (usbd_dev) usbd_poll(usbd_dev, 0); }