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 "libc.h"
#include "gpio.h" #include "gpio.h"
void spi_cb_rx(uint8_t *data, int len) {};
#include "drivers/drivers.h" #include "drivers/drivers.h"
#include "drivers/spi.h" #include "drivers/spi.h"

View File

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

View File

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

View File

@ -17,6 +17,10 @@ void spi_init() {
NVIC_EnableIRQ(DMA2_Stream3_IRQn); NVIC_EnableIRQ(DMA2_Stream3_IRQn);
//NVIC_EnableIRQ(SPI1_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) // setup interrupt on falling edge of SPI enable (on PA4)
SYSCFG->EXTICR[2] = SYSCFG_EXTICR2_EXTI4_PA; SYSCFG->EXTICR[2] = SYSCFG_EXTICR2_EXTI4_PA;
EXTI->IMR = (1 << 4); EXTI->IMR = (1 << 4);
@ -39,6 +43,12 @@ void spi_tx_dma(void *addr, int len) {
DMA2_Stream3->CR |= DMA_SxCR_TCIE; DMA2_Stream3->CR |= DMA_SxCR_TCIE;
SPI1->CR2 |= SPI_CR2_TXDMAEN; 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) { void spi_rx_dma(void *addr, int len) {
@ -64,11 +74,22 @@ void spi_rx_dma(void *addr, int len) {
// ***************************** SPI IRQs ***************************** // ***************************** SPI IRQs *****************************
// can't go on the stack cause it's DMAed
uint8_t spi_tx_buf[0x44];
// SPI RX // SPI RX
void DMA2_Stream2_IRQHandler(void) { void DMA2_Stream2_IRQHandler(void) {
// ack // ack
DMA2->LIFCR = DMA_LIFCR_CTCIF2; 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 // SPI TX
@ -76,6 +97,10 @@ void DMA2_Stream3_IRQHandler(void) {
// ack // ack
DMA2->LIFCR = DMA_LIFCR_CTCIF3; DMA2->LIFCR = DMA_LIFCR_CTCIF3;
#ifdef DEBUG_SPI
puts("SPI handshake\n");
#endif
// reset handshake back to pull up // reset handshake back to pull up
GPIOB->MODER &= ~(GPIO_MODER_MODER0); GPIOB->MODER &= ~(GPIO_MODER_MODER0);
GPIOB->PUPDR |= GPIO_PUPDR_PUPDR0_0; 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 #ifdef PANDA
int spi_cb_rx(uint8_t *data, int len, uint8_t *data_out) {
// 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);
// data[0] = endpoint // data[0] = endpoint
// data[2] = length // data[2] = length
// data[4:] = data // data[4:] = data
int *resp_len = (int*)spi_tx_buf;
*resp_len = 0; int resp_len = 0;
switch (data[0]) { switch (data[0]) {
case 0: case 0:
// control transfer // 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; break;
case 1: case 1:
// ep 1, read // 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; break;
case 2: case 2:
// ep 2, send serial // 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); usb_cb_ep3_out(data+4, data[2], 0);
break; break;
} }
spi_tx_dma(spi_tx_buf, 0x44); return resp_len;
// 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);
} }
#else #else
void spi_cb_rx(uint8_t *data, int len) {}; int spi_cb_rx(uint8_t *data, int len) { return 0; };
#endif #endif
@ -460,7 +449,7 @@ int main() {
// set PWM // set PWM
fan_init(); fan_init();
fan_set_speed(65535); fan_set_speed(0);
puts("**** INTERRUPTS ON ****\n"); puts("**** INTERRUPTS ON ****\n");

View File

@ -1,28 +1,84 @@
/*void lock_bootloader() { // can't go on the stack cause it's DMAed
if (FLASH->OPTCR & FLASH_OPTCR_nWRP_0) { uint8_t spi_tx_buf[0x44];
FLASH->OPTKEYR = 0x08192A3B;
FLASH->OPTKEYR = 0x4C5D6E7F;
// write protect the bootloader uint32_t *prog_ptr;
FLASH->OPTCR &= ~FLASH_OPTCR_nWRP_0; int unlocked = 0;
// OPT program int spi_cb_rx(uint8_t *data, int len, uint8_t *data_out) {
FLASH->OPTCR |= FLASH_OPTCR_OPTSTRT; // get serial number even in bootstub mode
while (FLASH->SR & FLASH_SR_BSY); if (memcmp("\x00\x00\x00\x00\x40\xD0\x00\x00\x00\x00\x20\x00", data, 0xC) == 0) {
memcpy(data_out, (void *)0x1fff79e0, 0x20);
// relock it return 0x20;
FLASH->OPTCR |= FLASH_OPTCR_OPTLOCK;
// reset
NVIC_SystemReset();
} }
}*/
// 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);
//*(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() { void spi_flasher() {
// green LED on for flashing __disable_irq();
GPIOC->MODER |= GPIO_MODER_MODER6_0;
GPIOC->ODR &= ~(1 << 6);
RCC->AHB1ENR |= RCC_AHB1ENR_DMA2EN; RCC->AHB1ENR |= RCC_AHB1ENR_DMA2EN;
RCC->APB2ENR |= RCC_APB2ENR_SPI1EN; 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) | GPIOA->AFR[0] = GPIO_AF5_SPI1 << (4*4) | GPIO_AF5_SPI1 << (5*4) |
GPIO_AF5_SPI1 << (6*4) | GPIO_AF5_SPI1 << (7*4); GPIO_AF5_SPI1 << (6*4) | GPIO_AF5_SPI1 << (7*4);
// blue LED on for flashing
set_led(LED_BLUE, 1);
// flasher // flasher
spi_init(); spi_init();
__enable_irq();
unsigned char spi_rx_buf[0x14]; while (1) { }
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);
}
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); SPIMasterSendData(SpiNum_HSPI, &spiData);
// give the ST time to be ready, up to 1s // 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 // TODO: handle this better
if (gpio_input_get() & (1 << 4)) os_printf("ERROR: SPI receive failed\n"); 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); SPIMasterRecvData(SpiNum_HSPI, &spiData);
int length = recvData[0]; int length = recvData[0];
if (length > 0x40) {
os_printf("SPI: BAD LENGTH RECEIVED\n");
}
// got response, 0x40 works, 0x44 does not // got response, 0x40 works, 0x44 does not
spiData.data = recvData+1; spiData.data = recvData+1;
spiData.dataLen = recvDataLen; spiData.dataLen = recvDataLen;

View File

@ -35,43 +35,60 @@ LOCAL os_timer_t ota_reboot_timer;
#define FIRMWARE_SIZE 503808 #define FIRMWARE_SIZE 503808
void st_flash() { void ICACHE_FLASH_ATTR st_flash() {
int i; int i;
// stupid watchdog test if (st_firmware != NULL) {
//system_soft_wdt_stop(); // stupid watchdog test
//system_soft_wdt_stop();
// boot mode // boot mode
st_set_boot_mode(1); os_printf("st_flash: enter boot mode\n");
st_set_boot_mode(1);
// unlock flash // echo
st_cmd(0x10, 0, NULL); os_printf("st_flash: wait for echo\n");
st_cmd(0xf, 0, NULL); int i;
for (i = 0; i < 10; i++) {
if (st_cmd(0xf, 0, NULL) == 1) break;
os_printf(" miss: %d\n", i);
}
// erase sector 1 // unlock flash
st_cmd(0x11, 1, NULL); os_printf("st_flash: unlock flash\n");
st_cmd(0xf, 0, NULL); st_cmd(0x10, 0, NULL);
if (real_content_length >= 16384) { // erase sector 1
// erase sector 2 os_printf("st_flash: erase sector 1\n");
st_cmd(0x11, 2, NULL); 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);
}
// real content length will always be 0x10 aligned
os_printf("st_flash: flashing\n");
for (i = 0; i < real_content_length; i += 0x10) {
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();
} }
// real content length will always be 0x10 aligned
for (i = 0; i < real_content_length; i += 0x10) {
st_cmd(0x12, 4, &st_firmware[i]);
system_soft_wdt_feed();
}
// reboot into normal mode
st_set_boot_mode(0);
// done with this
os_free(st_firmware);
// watchdog done
//system_soft_wdt_restart();
} }
typedef enum { typedef enum {
@ -87,7 +104,7 @@ typedef enum {
web_state_t state = NOT_STARTED; web_state_t state = NOT_STARTED;
int esp_address, esp_address_erase_limit, start_address; 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; int i;
for (i=0;i<len;i++) { for (i=0;i<len;i++) {
if (i!=0 && (i%0x10)==0) os_printf("\n"); if (i!=0 && (i%0x10)==0) os_printf("\n");
@ -96,7 +113,7 @@ void hexdump(char *data, int len) {
os_printf("\n"); os_printf("\n");
} }
void st_reset() { void ICACHE_FLASH_ATTR st_reset() {
// reset the ST // reset the ST
gpio16_output_conf(); gpio16_output_conf();
gpio16_output_set(0); gpio16_output_set(0);
@ -105,7 +122,7 @@ void st_reset() {
os_delay_us(10000); 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) { if (boot_mode) {
// boot mode (pull low) // boot mode (pull low)
gpio_output_set(0, (1 << 4), (1 << 4), 0); 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); gpio_output_set((1 << 4), 0, (1 << 4), 0);
st_reset(); 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]; uint32_t __dat[0x14];
char *dat = (char *)__dat; char *dat = (char *)__dat;
memset(dat, 0, 0x14); memset(dat, 0, 0x14);
@ -127,10 +147,31 @@ int st_cmd(int d1, int d2, char *data) {
dat[2] = d2; dat[2] = d2;
dat[3] = 0xFF^d2; dat[3] = 0xFF^d2;
if (data != NULL) memcpy(dat+4, data, 0x10); if (data != NULL) memcpy(dat+4, data, 0x10);
hexdump(dat, 0x14); //hexdump(dat, 0x14);
spi_comm(dat, 0x14, recv, 0x40); 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) { 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 // 0x1000 = user1.bin
// 0x81000 = user2.bin // 0x81000 = user2.bin
// 0x3FE000 = blank.bin // 0x3FE000 = blank.bin
os_printf("init st firmware\n"); os_printf("init esp firmware\n");
char *cl = strstr(data, "Content-Length: "); char *cl = strstr(data, "Content-Length: ");
if (cl != NULL) { if (cl != NULL) {
// get content length // get content length