#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;iDmaBaseAddress->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