diff options
Diffstat (limited to 'sw/Core/Src/spi.h')
| -rwxr-xr-x | sw/Core/Src/spi.h | 443 |
1 files changed, 443 insertions, 0 deletions
diff --git a/sw/Core/Src/spi.h b/sw/Core/Src/spi.h new file mode 100755 index 0000000..9affd1f --- /dev/null +++ b/sw/Core/Src/spi.h @@ -0,0 +1,443 @@ +#define AVG_GRAINBUF_SAMPLE_SIZE 68 // 2 extra for interpolation, 2 extra for SPI address at the start +#define GRAINBUF_BUDGET (AVG_GRAINBUF_SAMPLE_SIZE*32) +#define MAX_SPI_STATE 32 + +#define MAX_SAMPLE_LEN (1024*1024*2) // max sample length in samples + +int grainpos[32]; +s16 grainbuf[GRAINBUF_BUDGET]; +s16 grainbufend[32]; // for each of the 32 grain fetches, where does it end in the grainbuf? +u8 spibigtx[256 + 4]; +u8 spibigrx[256 + 4]; +#define EXPANDER_ZERO 0x800 +#define EXPANDER_RANGE 0x7ff +#define EXPANDER_MAX 0xfff +u16 expander_out[4] = { EXPANDER_ZERO,EXPANDER_ZERO,EXPANDER_ZERO,EXPANDER_ZERO }; + +int spi_readgrain_dma(int gi); +volatile u8 spistate=0; +u32 startspi; +u8 alexdmamode; +volatile u32 spiduration; +volatile u8 dummy; +static inline void spidelay(void) { + for (int i = 0; i < 10; ++i) dummy++; + +} + +void resetspistate(void) { + spistate = 0; + spiduration = RDTSC() - startspi; + alexdmamode = 0; +#ifndef EMU + GPIOA->BSRR = 1<<8; // DAC cs high +#endif +} + +void spi_update_dac(int dacchan); + + +void spi_read_done(void) { + if (spistate >= MAX_SPI_STATE) { +#ifndef EMU + GPIOA->BSRR = 1<<8; // DAC cs high +#endif + if (spistate == MAX_SPI_STATE+4) { + resetspistate(); + } else { + int dacchan = spistate-MAX_SPI_STATE; + spi_update_dac(dacchan); + } + } + else { + spi_readgrain_dma(spistate); + } +} + +#ifdef EMU +extern s16 _flashram[8 * MAX_SAMPLE_LEN]; +s16 _flashram[8* MAX_SAMPLE_LEN]; +#ifndef WASM +FILE* flashfile = 0; +#endif +void spi_wait(void){} +int spi_writeenable(void) { return 0; } +int spi_readid(void) { return 0; } +void spi_setchip(uint32_t addr) {} +int spi_waitnotbusy(const char *msg, void(*callback)(void)) { return 0; } +int spi_erase64k(u32 addr, void (*callback)(void)) { + memset(_flashram + addr / 2, -1, 65536); +#ifndef WASM + if (flashfile) { + fseek(flashfile, addr, 0); + fwrite(_flashram + addr / 2, 1, 65536, flashfile); + fflush(flashfile); + } +#endif + for (int i = 0; i < 16; ++i) { + HAL_Delay(2); + if (callback) callback(); + } + return 0; +} +void spiopen(void) { +#ifndef WASM + if (!flashfile) { + flashfile = fopen("flashspi.raw", "r+b"); + if (!flashfile) { + flashfile = fopen("flashspi.raw", "wb"); + if (flashfile) { + u8 zero[1024] = {0}; + for (int i = 0; i < (MAX_SAMPLE_LEN*16)/1024; ++i) + fwrite(zero, 1, 1024, flashfile); + fclose(flashfile); + flashfile = fopen("flashspi.raw", "r+b"); + } + } + if (flashfile) { + fseek(flashfile, 0, 0); + fread(_flashram, 16, MAX_SAMPLE_LEN, flashfile); + } + } +#endif +} + +int spi_write256(u32 addr) { + spiopen(); + memcpy(_flashram+addr/2,spibigtx+4,256); +#ifndef WASM + if (flashfile) { + fseek(flashfile, addr, 0); + fwrite(_flashram + addr / 2, 1, 256, flashfile); + fflush(flashfile); + } +#endif + return 0; +} +int spi_read256(u32 addr) { + memcpy(spibigrx+4, _flashram + addr / 2, 256); + return 0; +} + + +int spi_readgrain_dma(int gi) { + spiopen(); + spistate = gi; + if (spistate == 0) + startspi = RDTSC(); + ++spistate; + int start = 0; + if (gi) start = grainbufend[gi - 1]; + int len = grainbufend[gi] - start; + u32 addr = grainpos[gi]; + + //for (int i = 0; i < len; ++i) + // grainbuf[start + i] = ((addr + i - 2) * 256); + + if (len>2) + memcpy(((u8*)&grainbuf[start])+4,_flashram+(addr&(MAX_SAMPLE_LEN*8-1)),len*2-4); + spi_read_done(); + return 0; +} +#else + +volatile bool spidone = false; + +void spi_wait(void) { + while (!spidone) + ; + spidone = false; +} + +#define CHECKRV(spirv, msg) if (spirv!=0 ) DebugLog("SPI ERROR %d " msg "\r\n", spirv); + +#ifdef NEW_PINOUT +#define SPI_PORT GPIOE +#define SPI_CS0_PIN_ GPIO_PIN_1 +#define SPI_CS1_PIN_ GPIO_PIN_0 +#else +#define SPI_PORT GPIOD +#define SPI_CS0_PIN_ GPIO_PIN_0 +#define SPI_CS1_PIN_ GPIO_PIN_0 +#endif +u8 curspipin_=SPI_CS0_PIN_; +void spi_setchip(u32 addr) { + curspipin_ = (addr&(1<<24)) ? SPI_CS1_PIN_ : SPI_CS0_PIN_; +} +void spi_setexpanderdac(void) { + curspipin_ = 0; + hspi2.Instance->CR1 &= ~(1 | 64); + hspi2.Instance->CR1 |= 64; + SPI_PORT->BSRR = SPI_CS1_PIN_ | SPI_CS0_PIN_; + GPIOA->BRR = 1<<8; // dac cs low +} +static inline void spi_assert_cs(void) { + SPI_PORT->BSRR = SPI_CS1_PIN_ | SPI_CS0_PIN_; + hspi2.Instance->CR1 &= ~( 64); + hspi2.Instance->CR1 |= 1 | 64; + + SPI_PORT->BRR = curspipin_; +} +static inline void spi_release_cs(void) { + SPI_PORT->BSRR = SPI_CS1_PIN_ | SPI_CS0_PIN_; +} +int spi_writeenable(void) { + u8 spitxbuf[1] = { 6 }; + u8 spirxbuf[1]; + spi_assert_cs(); + spidelay(); + int spirv = HAL_SPI_TransmitReceive(&hspi2, (uint8_t*) spitxbuf, (uint8_t*) spirxbuf, 1, -1); + CHECKRV(spirv,"spi_writeenable"); + spi_release_cs(); + spidelay(); +// if (spirv==0) spi_wait(); + return spirv; +} + +int spi_readid(void) { + u8 spitxbuf[6] = { 0x90, 0, 0, 0, 0, 0 }; + u8 spirxbuf[6] = { 0 }; + spi_assert_cs(); + spidelay(); + int spirv = HAL_SPI_TransmitReceive(&hspi2, (uint8_t*) spitxbuf, (uint8_t*) spirxbuf, 6, -1); + CHECKRV(spirv,"spi_readid"); + spi_release_cs(); + spidelay(); + +// if (spirv==0) spi_wait(); + return (spirv == 0) ? (spirxbuf[4] + (spirxbuf[5] << 8)) : -1; +} + +int spi_readstatus(void) { + u8 spitxbuf[2] = { 5, 0 }; + u8 spirxbuf[2] = { 0 }; + spi_assert_cs(); + spidelay(); + int spirv = HAL_SPI_TransmitReceive(&hspi2, (uint8_t*) spitxbuf, (uint8_t*) spirxbuf, 2, -1); + CHECKRV(spirv,"spi_readstatus1"); + spi_release_cs(); + spidelay(); + return (spirv == 0) ? (spirxbuf[1]) : -1; +} + +int spi_waitnotbusy(const char *msg, void(*callback)(void)) { + int spirv = 0; +// spi_wait(); + int i = millis(); + u8 spitxbuf[1] = { 5 }; + u8 spirxbuf[1] = { 23 }; + spi_assert_cs(); + + spirv = HAL_SPI_TransmitReceive(&hspi2, (uint8_t*) spitxbuf, (uint8_t*) spirxbuf, 1, -1); + CHECKRV(spirv,"spi_waitnotbusy1"); + spirxbuf[0] = 0xff; + while (spirxbuf[0] & 1) { + + if (callback) + callback(); + + spirxbuf[0] = 0; + spirv=HAL_SPI_TransmitReceive(&hspi2, (uint8_t*) spitxbuf, (uint8_t*) spirxbuf, 1, -1); + CHECKRV(spirv,"spi_waitnotbusy2"); +// DebugLog("%02x ", spirxbuf[0]); + if (spirv) break; + } + spi_release_cs(); + spidelay(); + int t = millis() - i; + if (t > 10) + DebugLog("flash write/erase operation [%s] took %dms\r\n", msg, t); + return spirv; +} +int spi_read256(u32 addr); + +int spi_erase64k(u32 addr, void (*callback)(void)) { + spi_setchip(addr); + spi_writeenable(); + u8 spitxbuf[4] = { 0xd8, addr >> 16, addr >> 8, addr }; + u8 spirxbuf[4]; + DebugLog("spi erase %d\r\n", addr); + spi_assert_cs(); + spidelay(); + int spirv = HAL_SPI_TransmitReceive(&hspi2, (uint8_t*) spitxbuf, (uint8_t*) spirxbuf, 4, -1); + CHECKRV(spirv,"spi_erase1"); + spi_release_cs(); + spidelay(); + if (spirv == 0) + spirv = spi_waitnotbusy("erase", callback); + else { + DebugLog("HAL_SPI_TransmitReceive returned %d in erase\r\n", spirv); + } + /* + memset(spibigrx, 0, sizeof(spibigrx)); + spi_read256(addr); + for (int i = 0; i < 256; ++i) if (spibigrx[i + 4] != (u8)(255)) { + DebugLog("erase fail at %d\r\n", addr+i); + } + */ + return spirv; +} + +int spi_write256(u32 addr) { + spi_setchip(addr); + spi_writeenable(); + spibigtx[0] = 2; + spibigtx[1] = addr >> 16; + spibigtx[2] = addr >> 8; + spibigtx[3] = addr >> 0; + spi_assert_cs(); + + spidelay(); + int spirv = HAL_SPI_TransmitReceive(&hspi2, (uint8_t*) spibigtx, (uint8_t*) spibigrx, 4 + 256, -1); + CHECKRV(spirv,"spi_write256"); + + spi_release_cs(); + spidelay(); + + if (spirv == 0) + spirv = spi_waitnotbusy("write", 0); + + if (0) { + spi_read256(addr); + if (memcmp(spibigrx+4,spibigtx+4,256)!=0) { + DebugLog("spi didnt read what I wrote? %d\r\n", addr); + } + } + + return spirv; +} + +int spi_read256(u32 addr) { + spibigtx[0] = 3; + spibigtx[1] = addr >> 16; + spibigtx[2] = addr >> 8; + spibigtx[3] = addr >> 0; + spi_setchip(addr); + spi_assert_cs(); + + spidelay(); + int spirv = HAL_SPI_TransmitReceive(&hspi2, (uint8_t*) spibigtx, (uint8_t*) spibigrx, 4 + 256, -1); + CHECKRV(spirv,"spi_read256"); + spi_release_cs(); + spidelay(); + return spirv; +} + + + +static void DMA_SetConfig(DMA_HandleTypeDef *hdma, uint32_t SrcAddress, uint32_t DstAddress, uint32_t DataLength) { + hdma->DmaBaseAddress->IFCR = (DMA_ISR_GIF1 << (hdma->ChannelIndex & 0x1CU)); /* Clear all flags */ + hdma->Instance->CNDTR = DataLength; + if ((hdma->Init.Direction) == DMA_MEMORY_TO_PERIPH) { + hdma->Instance->CPAR = DstAddress; + hdma->Instance->CMAR = SrcAddress; + } else { + hdma->Instance->CPAR = SrcAddress; + hdma->Instance->CMAR = DstAddress; + } +} + +void setup_spi_alex_dma(uint32_t txaddr, uint32_t rxaddr, int len) { // len is in 8 bit words + // ALEX DMA MODE! fewer interrupts; simpler code. + alexdmamode = 1; + CLEAR_BIT(hspi2.Instance->CR2, SPI_CR2_LDMATX | SPI_CR2_LDMARX); // Reset the threshold bit + SET_BIT(hspi2.Instance->CR2, SPI_RXFIFO_THRESHOLD); // Set RX Fifo threshold according the reception data length: 8bit + // config rx dma - transfer complete callback + __HAL_DMA_DISABLE(hspi2.hdmarx); + DMA_SetConfig(hspi2.hdmarx, (uint32_t) &hspi2.Instance->DR, rxaddr, len); + __HAL_DMA_DISABLE_IT(hspi2.hdmarx, (DMA_IT_HT | DMA_IT_TE)); + __HAL_DMA_ENABLE_IT(hspi2.hdmarx, (DMA_IT_TC)); + __HAL_DMA_ENABLE(hspi2.hdmarx); + SET_BIT(hspi2.Instance->CR2, SPI_CR2_RXDMAEN); // Enable Rx DMA Request + + // config tx dma - no interrupts + __HAL_DMA_DISABLE(hspi2.hdmatx); + DMA_SetConfig(hspi2.hdmatx, txaddr, (uint32_t) &hspi2.Instance->DR, len); + __HAL_DMA_DISABLE_IT(hspi2.hdmatx, (DMA_IT_HT | DMA_IT_TE | DMA_IT_TC)); + __HAL_DMA_ENABLE(hspi2.hdmatx); + if ((hspi2.Instance->CR1 & SPI_CR1_SPE) != SPI_CR1_SPE) + __HAL_SPI_ENABLE(&hspi2); // Enable SPI peripheral + SET_BIT(hspi2.Instance->CR2, SPI_CR2_TXDMAEN); +} + +static u16 daccmd, dacdummy; +void spi_update_dac(int dacchan) { + spistate=MAX_SPI_STATE+dacchan + 1; // the NEXT state + + int data = expander_out[dacchan & 3]; + + daccmd = (2<<14) + ((dacchan&3)<<12) + (data & 0xfff); + daccmd=(daccmd>>8) | (daccmd<<8); + spi_setexpanderdac(); // assert cs for dac + setup_spi_alex_dma((uint32_t)&daccmd, (uint32_t)&dacdummy, 2); +} + + + +int spi_readgrain_dma(int gi) { + spi_release_cs(); + u32 addr; +again: + addr = grainpos[gi] * 2; + spibigtx[0] = 3; + spibigtx[1] = addr >> 16; + spibigtx[2] = addr >> 8; + spibigtx[3] = addr >> 0; + spistate = gi; + if (spistate==0) + startspi = RDTSC(); + ++spistate; + int start = 0; + if (gi) start = grainbufend[gi - 1]; + int len = grainbufend[gi] - start; + + if (len<=2) { + if (spistate==MAX_SPI_STATE) { + spi_update_dac(0); +// resetspistate(); + return 0; + } + ++gi; + goto again; + } + + + if (0) { + for (int i=0;i<len;++i) + + grainbuf[start+i]=((addr/2+i-2)*256); + if (spistate==MAX_SPI_STATE) { + spi_update_dac(0); +// resetspistate(); + return 0; + } + ++gi; goto again; + } + spi_setchip(addr); + spi_assert_cs(); + + setup_spi_alex_dma((uint32_t) spibigtx, (uint32_t) (grainbuf+start), len * 2); + + return 0; +} + + +void alexdmadone(void) { + // replacement irq handler for the HAL guff. + DMA_HandleTypeDef *hdma = hspi2.hdmarx; /*!< SPI Rx DMA Handle parameters */ + uint32_t flag_it = hdma->DmaBaseAddress->ISR; + uint32_t source_it = hdma->Instance->CCR; + if (((flag_it & (DMA_FLAG_TC1 << (hdma->ChannelIndex & 0x1CU))) != 0U) && ((source_it & DMA_IT_TC) != 0U)) { + __HAL_DMA_DISABLE_IT(hdma, DMA_IT_TE | DMA_IT_TC | DMA_IT_HT); + hdma->DmaBaseAddress->IFCR = (DMA_ISR_TCIF1 << (hdma->ChannelIndex & 0x1CU)); /* Clear the transfer complete flag */ + spi_read_done(); + } +} + +/* + void HAL_SPI_TxRxCpltCallback(SPI_HandleTypeDef *hspi) + { + spidone=true; + } + */ +#endif |
