openpilot is an open source driver assistance system. openpilot performs the functions of Automated Lane Centering and Adaptive Cruise Control for over 200 supported car makes and models.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

109 lines
3.3 KiB

#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