478 lines
13 KiB
C
478 lines
13 KiB
C
/*
|
|
* 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 <http://www.gnu.org/licenses/>.
|
|
*
|
|
* Author: Daniele Lacamera
|
|
*
|
|
*
|
|
*/
|
|
|
|
#include <unicore-mx/stm32/gpio.h>
|
|
#include <unicore-mx/stm32/rcc.h>
|
|
#include <unicore-mx/stm32/usart.h>
|
|
#include <unicore-mx/cm3/nvic.h>
|
|
#include <unicore-mx/usbd/usbd.h>
|
|
#include <unicore-mx/usbd/class/msc.h>
|
|
#include <unicore-mx/stm32/otg_fs.h>
|
|
|
|
|
|
#include <stdlib.h>
|
|
#include <stdint.h>
|
|
#include <string.h>
|
|
#include <stdio.h>
|
|
|
|
#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);
|
|
}
|
|
|