refactor SPI and make flasher reliable

This commit is contained in:
Firmware Batman 2017-07-24 12:31:47 -07:00
parent a2523f2d3a
commit 0a5a8ab5ec
8 changed files with 203 additions and 188 deletions

View File

@ -12,9 +12,6 @@
#include "libc.h"
#include "gpio.h"
void spi_cb_rx(uint8_t *data, int len) {};
#include "drivers/drivers.h"
#include "drivers/spi.h"

View File

@ -3,6 +3,7 @@
//#define DEBUG
//#define DEBUG_USB
//#define DEBUG_SPI
#ifdef STM32F4
#define PANDA

View File

@ -70,8 +70,7 @@ void timer_init(TIM_TypeDef *TIM, int psc);
// IRQs: DMA2_Stream2, DMA2_Stream3, EXTI4
void spi_init();
void spi_cb_rx(uint8_t *data, int len);
void spi_tx_dma(void *addr, int len);
int spi_cb_rx(uint8_t *data, int len, uint8_t *data_out);
// ********************* CAN *********************

View File

@ -17,6 +17,10 @@ void spi_init() {
NVIC_EnableIRQ(DMA2_Stream3_IRQn);
//NVIC_EnableIRQ(SPI1_IRQn);
// reset handshake back to pull up
GPIOB->MODER &= ~(GPIO_MODER_MODER0);
GPIOB->PUPDR |= GPIO_PUPDR_PUPDR0_0;
// setup interrupt on falling edge of SPI enable (on PA4)
SYSCFG->EXTICR[2] = SYSCFG_EXTICR2_EXTI4_PA;
EXTI->IMR = (1 << 4);
@ -39,6 +43,12 @@ void spi_tx_dma(void *addr, int len) {
DMA2_Stream3->CR |= DMA_SxCR_TCIE;
SPI1->CR2 |= SPI_CR2_TXDMAEN;
// signal data is ready by driving low
// esp must be configured as input by this point
GPIOB->MODER &= ~(GPIO_MODER_MODER0);
GPIOB->MODER |= GPIO_MODER_MODER0_0;
GPIOB->ODR &= ~(GPIO_ODR_ODR_0);
}
void spi_rx_dma(void *addr, int len) {
@ -64,11 +74,22 @@ void spi_rx_dma(void *addr, int len) {
// ***************************** SPI IRQs *****************************
// can't go on the stack cause it's DMAed
uint8_t spi_tx_buf[0x44];
// SPI RX
void DMA2_Stream2_IRQHandler(void) {
// ack
DMA2->LIFCR = DMA_LIFCR_CTCIF2;
spi_cb_rx(spi_buf, 0x13);
int *resp_len = (int*)spi_tx_buf;
memset(spi_tx_buf, 0xaa, 0x44);
*resp_len = spi_cb_rx(spi_buf, 0x13, spi_tx_buf+4);
#ifdef DEBUG_SPI
puts("SPI write: ");
puth(*resp_len);
puts("\n");
#endif
spi_tx_dma(spi_tx_buf, *resp_len + 4);
}
// SPI TX
@ -76,6 +97,10 @@ void DMA2_Stream3_IRQHandler(void) {
// ack
DMA2->LIFCR = DMA_LIFCR_CTCIF3;
#ifdef DEBUG_SPI
puts("SPI handshake\n");
#endif
// reset handshake back to pull up
GPIOB->MODER &= ~(GPIO_MODER_MODER0);
GPIOB->PUPDR |= GPIO_PUPDR_PUPDR0_0;

View File

@ -358,25 +358,20 @@ int usb_cb_control_msg(USB_Setup_TypeDef *setup, uint8_t *resp, int hardwired) {
}
#ifdef PANDA
// can't go on the stack cause it's DMAed
uint8_t spi_tx_buf[0x44];
void spi_cb_rx(uint8_t *data, int len) {
memset(spi_tx_buf, 0xaa, 0x44);
int spi_cb_rx(uint8_t *data, int len, uint8_t *data_out) {
// data[0] = endpoint
// data[2] = length
// data[4:] = data
int *resp_len = (int*)spi_tx_buf;
*resp_len = 0;
int resp_len = 0;
switch (data[0]) {
case 0:
// control transfer
*resp_len = usb_cb_control_msg((USB_Setup_TypeDef *)(data+4), spi_tx_buf+4, 0);
resp_len = usb_cb_control_msg((USB_Setup_TypeDef *)(data+4), data_out, 0);
break;
case 1:
// ep 1, read
*resp_len = usb_cb_ep1_in(spi_tx_buf+4, 0x40, 0);
resp_len = usb_cb_ep1_in(data_out, 0x40, 0);
break;
case 2:
// ep 2, send serial
@ -387,18 +382,12 @@ void spi_cb_rx(uint8_t *data, int len) {
usb_cb_ep3_out(data+4, data[2], 0);
break;
}
spi_tx_dma(spi_tx_buf, 0x44);
// signal data is ready by driving low
// esp must be configured as input by this point
GPIOB->MODER &= ~(GPIO_MODER_MODER0);
GPIOB->MODER |= GPIO_MODER_MODER0_0;
GPIOB->ODR &= ~(GPIO_ODR_ODR_0);
return resp_len;
}
#else
void spi_cb_rx(uint8_t *data, int len) {};
int spi_cb_rx(uint8_t *data, int len) { return 0; };
#endif
@ -460,7 +449,7 @@ int main() {
// set PWM
fan_init();
fan_set_speed(65535);
fan_set_speed(0);
puts("**** INTERRUPTS ON ****\n");

View File

@ -1,27 +1,83 @@
/*void lock_bootloader() {
if (FLASH->OPTCR & FLASH_OPTCR_nWRP_0) {
FLASH->OPTKEYR = 0x08192A3B;
FLASH->OPTKEYR = 0x4C5D6E7F;
// can't go on the stack cause it's DMAed
uint8_t spi_tx_buf[0x44];
// write protect the bootloader
FLASH->OPTCR &= ~FLASH_OPTCR_nWRP_0;
uint32_t *prog_ptr;
int unlocked = 0;
// OPT program
FLASH->OPTCR |= FLASH_OPTCR_OPTSTRT;
int spi_cb_rx(uint8_t *data, int len, uint8_t *data_out) {
// get serial number even in bootstub mode
if (memcmp("\x00\x00\x00\x00\x40\xD0\x00\x00\x00\x00\x20\x00", data, 0xC) == 0) {
memcpy(data_out, (void *)0x1fff79e0, 0x20);
return 0x20;
}
// flasher mode
if (data[0] == (0xff^data[1]) &&
data[2] == (0xff^data[3])) {
int sec;
memset(data_out, 0, 4);
memcpy(data_out+4, "\xde\xad\xd0\x0d", 4);
data_out[0] = 0xff;
data_out[2] = data[0];
data_out[3] = data[1];
switch (data[0]) {
case 0xf:
// echo
data_out[1] = 0xff;
break;
case 0x10:
// unlock flash
if (FLASH->CR & FLASH_CR_LOCK) {
FLASH->KEYR = 0x45670123;
FLASH->KEYR = 0xCDEF89AB;
data_out[1] = 0xff;
}
set_led(LED_GREEN, 1);
unlocked = 1;
prog_ptr = (uint32_t *)0x8004000;
break;
case 0x11:
// erase
sec = data[2] & 0xF;
// don't erase the bootloader
if (sec != 0 && sec < 12 && unlocked) {
FLASH->CR = (sec << 3) | FLASH_CR_SER;
FLASH->CR |= FLASH_CR_STRT;
while (FLASH->SR & FLASH_SR_BSY);
data_out[1] = 0xff;
}
break;
case 0x12:
if (data[2] <= 4 && unlocked) {
set_led(LED_RED, 0);
for (int i = 0; i < data[2]; i++) {
// program byte 1
FLASH->CR = FLASH_CR_PSIZE_1 | FLASH_CR_PG;
*prog_ptr = *(uint32_t*)(data+4+(i*4));
while (FLASH->SR & FLASH_SR_BSY);
// relock it
FLASH->OPTCR |= FLASH_OPTCR_OPTLOCK;
//*(uint64_t*)(&spi_tx_buf[0x30+(i*4)]) = *prog_ptr;
prog_ptr++;
}
set_led(LED_RED, 1);
data_out[1] = 0xff;
}
break;
case 0x13:
// reset
NVIC_SystemReset();
break;
default:
break;
}
}
return 8;
}
}*/
void spi_flasher() {
// green LED on for flashing
GPIOC->MODER |= GPIO_MODER_MODER6_0;
GPIOC->ODR &= ~(1 << 6);
__disable_irq();
RCC->AHB1ENR |= RCC_AHB1ENR_DMA2EN;
RCC->APB2ENR |= RCC_APB2ENR_SPI1EN;
@ -32,112 +88,13 @@ void spi_flasher() {
GPIOA->AFR[0] = GPIO_AF5_SPI1 << (4*4) | GPIO_AF5_SPI1 << (5*4) |
GPIO_AF5_SPI1 << (6*4) | GPIO_AF5_SPI1 << (7*4);
// blue LED on for flashing
set_led(LED_BLUE, 1);
// flasher
spi_init();
__enable_irq();
unsigned char spi_rx_buf[0x14];
unsigned char spi_tx_buf[0x44];
int i;
int sec;
int rcv = 0;
int lastval = (GPIOA->IDR & (1 << 4));
uint32_t *prog_ptr = (uint32_t *)0x8004000;
while (1) {
int val = (GPIOA->IDR & (1 << 4));
if (!val && lastval) {
spi_rx_dma(spi_rx_buf, 0x14);
rcv = 1;
}
lastval = val;
if (rcv && (DMA2->LISR & DMA_LISR_TCIF2)) {
DMA2->LIFCR = DMA_LIFCR_CTCIF2;
rcv = 0;
memset(spi_tx_buf, 0, 0x44);
spi_tx_buf[0x40] = 0xde;
spi_tx_buf[0x41] = 0xad;
spi_tx_buf[0x42] = 0xd0;
spi_tx_buf[0x43] = 0x0d;
if (memcmp("\x00\x00\x00\x00\x40\xD0\x00\x00\x00\x00\x20\x00", spi_rx_buf, 0xC) == 0) {
*(uint32_t*)(&spi_tx_buf[0]) = 0x20;
memcpy(spi_tx_buf+4, (void *)0x1fff79e0, 0x20);
} else if (spi_rx_buf[0] == (0xff^spi_rx_buf[1]) &&
spi_rx_buf[2] == (0xff^spi_rx_buf[3])) {
spi_tx_buf[0] = 0xff;
*(uint32_t*)(&spi_tx_buf[4]) = FLASH->CR;
*(uint32_t*)(&spi_tx_buf[8]) = (uint32_t)prog_ptr;
// valid
switch (spi_rx_buf[0]) {
case 0x10:
// unlock flash
if (FLASH->CR & FLASH_CR_LOCK) {
FLASH->KEYR = 0x45670123;
FLASH->KEYR = 0xCDEF89AB;
spi_tx_buf[1] = 0xff;
}
break;
case 0x11:
// erase
sec = spi_rx_buf[2] & 0xF;
// don't erase the bootloader
if (sec != 0 && sec < 12) {
FLASH->CR = (sec << 3) | FLASH_CR_SER;
FLASH->CR |= FLASH_CR_STRT;
while (FLASH->SR & FLASH_SR_BSY);
spi_tx_buf[1] = 0xff;
}
break;
case 0x12:
if (spi_rx_buf[2] <= 4) {
set_led(LED_RED, 0);
for (i = 0; i < spi_rx_buf[2]; i++) {
// program byte 1
FLASH->CR = FLASH_CR_PSIZE_1 | FLASH_CR_PG;
*prog_ptr = *(uint32_t*)(spi_rx_buf+4+(i*4));
while (FLASH->SR & FLASH_SR_BSY);
*(uint64_t*)(&spi_tx_buf[0x30+(i*4)]) = *prog_ptr;
prog_ptr++;
}
set_led(LED_RED, 1);
spi_tx_buf[1] = 0xff;
}
break;
case 0x13:
// reset
NVIC_SystemReset();
break;
case 0x14:
// bootloader
/*enter_bootloader_mode = ENTER_BOOTLOADER_MAGIC;
NVIC_SystemReset();*/
break;
default:
break;
}
memcpy(spi_tx_buf+0x10, spi_rx_buf, 0x14);
while (1) { }
}
spi_tx_dma(spi_tx_buf, 0x44);
// signal data is ready by driving low
// esp must be configured as input by this point
GPIOB->MODER &= ~(GPIO_MODER_MODER0);
GPIOB->MODER |= GPIO_MODER_MODER0_0;
GPIOB->ODR &= ~(GPIO_ODR_ODR_0);
}
if (DMA2->LISR & DMA_LISR_TCIF3) {
DMA2->LIFCR = DMA_LIFCR_CTCIF3;
// reset handshake back to pull up
GPIOB->MODER &= ~(GPIO_MODER_MODER0);
GPIOB->PUPDR |= GPIO_PUPDR_PUPDR0_0;
}
}
}

View File

@ -56,7 +56,9 @@ static int ICACHE_FLASH_ATTR __spi_comm(char *dat, int len, uint32_t *recvData,
SPIMasterSendData(SpiNum_HSPI, &spiData);
// give the ST time to be ready, up to 1s
for (int i = 0;(gpio_input_get() & (1 << 4)) && i < 100000; i++) os_delay_us(10);
for (int i = 0;(gpio_input_get() & (1 << 4)) && i < 100000; i++) {
os_delay_us(10);
}
// TODO: handle this better
if (gpio_input_get() & (1 << 4)) os_printf("ERROR: SPI receive failed\n");
@ -70,6 +72,10 @@ static int ICACHE_FLASH_ATTR __spi_comm(char *dat, int len, uint32_t *recvData,
SPIMasterRecvData(SpiNum_HSPI, &spiData);
int length = recvData[0];
if (length > 0x40) {
os_printf("SPI: BAD LENGTH RECEIVED\n");
}
// got response, 0x40 works, 0x44 does not
spiData.data = recvData+1;
spiData.dataLen = recvDataLen;

View File

@ -35,44 +35,61 @@ LOCAL os_timer_t ota_reboot_timer;
#define FIRMWARE_SIZE 503808
void st_flash() {
void ICACHE_FLASH_ATTR st_flash() {
int i;
if (st_firmware != NULL) {
// stupid watchdog test
//system_soft_wdt_stop();
// boot mode
os_printf("st_flash: enter boot mode\n");
st_set_boot_mode(1);
// echo
os_printf("st_flash: wait for echo\n");
int i;
for (i = 0; i < 10; i++) {
if (st_cmd(0xf, 0, NULL) == 1) break;
os_printf(" miss: %d\n", i);
}
// unlock flash
os_printf("st_flash: unlock flash\n");
st_cmd(0x10, 0, NULL);
st_cmd(0xf, 0, NULL);
// erase sector 1
os_printf("st_flash: erase sector 1\n");
st_cmd(0x11, 1, NULL);
st_cmd(0xf, 0, NULL);
if (real_content_length >= 16384) {
// erase sector 2
os_printf("st_flash: erase sector 2\n");
st_cmd(0x11, 2, NULL);
st_cmd(0xf, 0, NULL);
}
// real content length will always be 0x10 aligned
os_printf("st_flash: flashing\n");
for (i = 0; i < real_content_length; i += 0x10) {
st_cmd(0x12, 4, &st_firmware[i]);
if (!st_cmd(0x12, 4, &st_firmware[i])) {
os_printf("st_flash: FAILED, BAILING\n");
break;
}
system_soft_wdt_feed();
}
// reboot into normal mode
os_printf("st_flash: rebooting\n");
st_set_boot_mode(0);
// done with this
os_free(st_firmware);
st_firmware = NULL;
// watchdog done
//system_soft_wdt_restart();
}
}
typedef enum {
NOT_STARTED,
@ -87,7 +104,7 @@ typedef enum {
web_state_t state = NOT_STARTED;
int esp_address, esp_address_erase_limit, start_address;
void hexdump(char *data, int len) {
void ICACHE_FLASH_ATTR hexdump(char *data, int len) {
int i;
for (i=0;i<len;i++) {
if (i!=0 && (i%0x10)==0) os_printf("\n");
@ -96,7 +113,7 @@ void hexdump(char *data, int len) {
os_printf("\n");
}
void st_reset() {
void ICACHE_FLASH_ATTR st_reset() {
// reset the ST
gpio16_output_conf();
gpio16_output_set(0);
@ -105,7 +122,7 @@ void st_reset() {
os_delay_us(10000);
}
void st_set_boot_mode(int boot_mode) {
void ICACHE_FLASH_ATTR st_set_boot_mode(int boot_mode) {
if (boot_mode) {
// boot mode (pull low)
gpio_output_set(0, (1 << 4), (1 << 4), 0);
@ -115,9 +132,12 @@ void st_set_boot_mode(int boot_mode) {
gpio_output_set((1 << 4), 0, (1 << 4), 0);
st_reset();
}
// float boot pin
gpio_output_set(0, 0, 0, (1 << 4));
}
int st_cmd(int d1, int d2, char *data) {
int ICACHE_FLASH_ATTR st_cmd(int d1, int d2, char *data) {
uint32_t __dat[0x14];
char *dat = (char *)__dat;
memset(dat, 0, 0x14);
@ -127,10 +147,31 @@ int st_cmd(int d1, int d2, char *data) {
dat[2] = d2;
dat[3] = 0xFF^d2;
if (data != NULL) memcpy(dat+4, data, 0x10);
hexdump(dat, 0x14);
//hexdump(dat, 0x14);
spi_comm(dat, 0x14, recv, 0x40);
return memcmp(recv+0x10, "\xde\xad\xd0\x0d", 4)==0;
//hexdump(recv, 0x44);
int good = memcmp(recv+2, "\xde\xad\xd0\x0d", 4)==0;
if (!good) {
os_printf("ST command failed!\n");
hexdump(recv, 0x44);
return 0;
}
if (((uint8_t*)recv)[6] != d1) {
os_printf("ST command WRONG\n");
hexdump(recv, 0x44);
return 0;
}
if (((uint8_t*)recv)[5] != 0xFF) {
os_printf("ST command logical fail\n");
hexdump(recv, 0x44);
return 0;
}
return 1;
}
static void ICACHE_FLASH_ATTR web_rx_cb(void *arg, char *data, uint16_t len) {
@ -182,7 +223,7 @@ static void ICACHE_FLASH_ATTR web_rx_cb(void *arg, char *data, uint16_t len) {
// 0x1000 = user1.bin
// 0x81000 = user2.bin
// 0x3FE000 = blank.bin
os_printf("init st firmware\n");
os_printf("init esp firmware\n");
char *cl = strstr(data, "Content-Length: ");
if (cl != NULL) {
// get content length