panda/board/stm32h7/llspi.h

110 lines
3.3 KiB
C

#if defined(ENABLE_SPI) || defined(BOOTSTUB)
// master -> panda DMA start
void llspi_mosi_dma(uint8_t *addr, int len) {
// disable DMA + SPI
register_clear_bits(&(SPI4->CFG1), SPI_CFG1_RXDMAEN);
DMA2_Stream2->CR &= ~DMA_SxCR_EN;
register_clear_bits(&(SPI4->CR1), SPI_CR1_SPE);
// drain the bus
while ((SPI4->SR & SPI_SR_RXP) != 0U) {
volatile uint8_t dat = SPI4->RXDR;
(void)dat;
}
// clear all pending
SPI4->IFCR |= (0x1FFU << 3U);
register_set(&(SPI4->IER), 0, 0x3FFU);
// setup destination and length
register_set(&(DMA2_Stream2->M0AR), (uint32_t)addr, 0xFFFFFFFFU);
DMA2_Stream2->NDTR = len;
// enable DMA + SPI
DMA2_Stream2->CR |= DMA_SxCR_EN;
register_set_bits(&(SPI4->CFG1), SPI_CFG1_RXDMAEN);
register_set_bits(&(SPI4->CR1), SPI_CR1_SPE);
}
// panda -> master DMA start
void llspi_miso_dma(uint8_t *addr, int len) {
// disable DMA + SPI
DMA2_Stream3->CR &= ~DMA_SxCR_EN;
register_clear_bits(&(SPI4->CFG1), SPI_CFG1_TXDMAEN);
register_clear_bits(&(SPI4->CR1), SPI_CR1_SPE);
// setup source and length
register_set(&(DMA2_Stream3->M0AR), (uint32_t)addr, 0xFFFFFFFFU);
DMA2_Stream3->NDTR = len;
// clear under-run while we were reading
SPI4->IFCR |= (0x1FFU << 3U);
// setup interrupt on TXC
register_set(&(SPI4->IER), (1U << SPI_IER_EOTIE_Pos), 0x3FFU);
// enable DMA + SPI
register_set_bits(&(SPI4->CFG1), SPI_CFG1_TXDMAEN);
DMA2_Stream3->CR |= DMA_SxCR_EN;
register_set_bits(&(SPI4->CR1), SPI_CR1_SPE);
}
static bool spi_tx_dma_done = false;
// master -> panda DMA finished
static void DMA2_Stream2_IRQ_Handler(void) {
// Clear interrupt flag
DMA2->LIFCR = DMA_LIFCR_CTCIF2;
spi_rx_done();
}
// panda -> master DMA finished
static void DMA2_Stream3_IRQ_Handler(void) {
ENTER_CRITICAL();
DMA2->LIFCR = DMA_LIFCR_CTCIF3;
spi_tx_dma_done = true;
EXIT_CRITICAL();
}
// panda TX finished
static void SPI4_IRQ_Handler(void) {
// clear flag
SPI4->IFCR |= (0x1FFU << 3U);
if (spi_tx_dma_done && ((SPI4->SR & SPI_SR_TXC) != 0U)) {
spi_tx_dma_done = false;
spi_tx_done(false);
}
}
void llspi_init(void) {
REGISTER_INTERRUPT(SPI4_IRQn, SPI4_IRQ_Handler, (SPI_IRQ_RATE * 2U), FAULT_INTERRUPT_RATE_SPI)
REGISTER_INTERRUPT(DMA2_Stream2_IRQn, DMA2_Stream2_IRQ_Handler, SPI_IRQ_RATE, FAULT_INTERRUPT_RATE_SPI_DMA)
REGISTER_INTERRUPT(DMA2_Stream3_IRQn, DMA2_Stream3_IRQ_Handler, SPI_IRQ_RATE, FAULT_INTERRUPT_RATE_SPI_DMA)
// Setup MOSI DMA
register_set(&(DMAMUX1_Channel10->CCR), 83U, 0xFFFFFFFFU);
register_set(&(DMA2_Stream2->CR), (DMA_SxCR_MINC | DMA_SxCR_TCIE), 0x1E077EFEU);
register_set(&(DMA2_Stream2->PAR), (uint32_t)&(SPI4->RXDR), 0xFFFFFFFFU);
// Setup MISO DMA, memory -> peripheral
register_set(&(DMAMUX1_Channel11->CCR), 84U, 0xFFFFFFFFU);
register_set(&(DMA2_Stream3->CR), (DMA_SxCR_MINC | DMA_SxCR_DIR_0 | DMA_SxCR_TCIE), 0x1E077EFEU);
register_set(&(DMA2_Stream3->PAR), (uint32_t)&(SPI4->TXDR), 0xFFFFFFFFU);
// Enable SPI
register_set(&(SPI4->IER), 0, 0x3FFU);
register_set(&(SPI4->CFG1), (7U << SPI_CFG1_DSIZE_Pos), SPI_CFG1_DSIZE_Msk);
register_set(&(SPI4->UDRDR), 0xcd, 0xFFFFU); // set under-run value for debugging
register_set(&(SPI4->CR1), SPI_CR1_SPE, 0xFFFFU);
register_set(&(SPI4->CR2), 0, 0xFFFFU);
NVIC_EnableIRQ(DMA2_Stream2_IRQn);
NVIC_EnableIRQ(DMA2_Stream3_IRQn);
NVIC_EnableIRQ(SPI4_IRQn);
}
#endif