static u8 spi_readwrite(u32 spi, u8 data) { while (!(SPI_SR(spi) & SPI_SR_TXE)) ; SPI_DR(spi) = data; while (!(SPI_SR(spi) & SPI_SR_RXNE)) ; return SPI_DR(spi); }
/** * send 1 byte blocking * return 1 on success */ uint8_t spi_write_byte(uint8_t data){ while(!(SPI_SR(Current_SPI) & SPI_SR_TXE)); SPI_DR(Current_SPI) = data; while(!(SPI_SR(Current_SPI) & SPI_SR_TXE)); while(!(SPI_SR(Current_SPI) & SPI_SR_RXNE)); (void)SPI_DR(Current_SPI); while(!(SPI_SR(Current_SPI) & SPI_SR_TXE)); while(SPI_SR(Current_SPI) & SPI_SR_BSY); return 1; }
void TBlockingSpiDmaJob::Run() { TaskId = TScheduler::GetCurrentTaskId(); CurrentJob = this; const uint32_t spi = FLASH_SPI_CHANNEL; const uint32_t dma = DMA1; assert(SPI_SR(spi) & SPI_SR_TXE); assert(~SPI_SR(spi) & SPI_SR_BSY); assert(!(SPI_SR(spi) & SPI_SR_RXNE)); { const uint32_t channel = FLASH_DMA_TX_CHANNEL; dma_channel_reset(dma, channel); dma_set_peripheral_address(dma, channel, reinterpret_cast<uint32_t>(&SPI_DR(spi))); dma_set_memory_address(dma, channel, reinterpret_cast<uint32_t>(Out)); dma_set_number_of_data(dma, channel, Len); dma_set_read_from_memory(dma, channel); dma_enable_memory_increment_mode(dma, channel); dma_set_peripheral_size(dma, channel, DMA_CCR_PSIZE_8BIT); dma_set_memory_size(dma, channel, DMA_CCR_MSIZE_8BIT); dma_set_priority(dma, channel, DMA_CCR_PL_LOW); // dma_enable_transfer_complete_interrupt(dma, channel); dma_enable_channel(dma, channel); } { const uint32_t channel = FLASH_DMA_RX_CHANNEL; dma_channel_reset(dma, channel); dma_set_peripheral_address(dma, channel, reinterpret_cast<uint32_t>(&SPI_DR(spi))); dma_set_number_of_data(dma, channel, Len); if (In != 0) { dma_set_memory_address(dma, channel, reinterpret_cast<uint32_t>(In)); dma_enable_memory_increment_mode(dma, channel); } else { dma_set_memory_address(dma, channel, reinterpret_cast<uint32_t>(&DummyPosition)); } dma_set_peripheral_size(dma, channel, DMA_CCR_PSIZE_8BIT); dma_set_memory_size(dma, channel, DMA_CCR_MSIZE_8BIT); dma_set_priority(dma, channel, DMA_CCR_PL_LOW); dma_enable_transfer_complete_interrupt(dma, channel); dma_enable_channel(dma, channel); } // Kick off the transfer spi_enable_rx_dma(spi); spi_enable_tx_dma(spi); // Wait for completion TScheduler::BlockUntil(&Finished); }
/** * Blocking rite data to current SPI * @param data - buffer with data * @param len - buffer length * @return 0 in case of error (or 1 in case of success) */ uint8_t spiWrite(uint8_t *data, uint16_t len){ uint16_t i; while(!(SPI_SR(Current_SPI) & SPI_SR_TXE)); for(i = 0; i < len; ++i){ SPI_DR(Current_SPI) = data[i]; while(!(SPI_SR(Current_SPI) & SPI_SR_TXE)); } while(!(SPI_SR(Current_SPI) & SPI_SR_RXNE)); (void)SPI_DR(Current_SPI); while(!(SPI_SR(Current_SPI) & SPI_SR_TXE)); while(SPI_SR(Current_SPI) & SPI_SR_BSY); return 1; }
int spi_transfer(spi_t spi, u16 data) { u32 r; while (!((r = SPI_SR(base_addr(spi))) & (SPI_SR_TXE | SPI_SR_ERROR))) ; if (r & SPI_SR_ERROR) return -SPI_TRANSFER_ERROR | r; SPI_DR(base_addr(spi)) = data; while (!((r = SPI_SR(base_addr(spi))) & (SPI_SR_RXNE | SPI_SR_ERROR))) ; if (r & SPI_SR_ERROR) return -SPI_TRANSFER_ERROR | r; return SPI_DR(base_addr(spi)); }
void spi_send(uint32_t spi, uint16_t data) { /* Wait for transfer finished. */ while (!(SPI_SR(spi) & SPI_SR_TXE)); /* Write data (8 or 16 bits, depending on DFF) into DR. */ SPI_DR(spi) = data; }
uint16_t spi_read(uint32_t spi) { /* Wait for transfer finished. */ while (!(SPI_SR(spi) & SPI_SR_RXNE)); /* Read the data (8 or 16 bits, depending on DFF bit) from DR. */ return SPI_DR(spi); }
/* Receive data using DMA. */ void rx_spi(void *data, uint16_t size){ if(DmaCleanupNeeded)cleanup_dma_spi(); /* This byte is sent continuously when rx_spi() receives data. */ static const uint8_t RxSpiDummyByte = 0x00; spi_enable_rx_dma(SPI3); dma_channel_reset(DMA1, DMA_CHANNEL2); dma_disable_channel(DMA1, DMA_CHANNEL2); dma_set_peripheral_address(DMA1, DMA_CHANNEL2, (uint32_t) &(SPI_DR(SPI3))); dma_set_memory_address(DMA1, DMA_CHANNEL2, (uint32_t) data); dma_set_number_of_data(DMA1, DMA_CHANNEL2, size); dma_set_priority(DMA1, DMA_CHANNEL2, DMA_CCR_PL_HIGH); dma_set_memory_size(DMA1, DMA_CHANNEL2, DMA_CCR_MSIZE_8BIT); dma_set_peripheral_size(DMA1, DMA_CHANNEL2, DMA_CCR_PSIZE_8BIT); dma_enable_memory_increment_mode(DMA1, DMA_CHANNEL2); dma_disable_peripheral_increment_mode(DMA1, DMA_CHANNEL2); dma_set_read_from_peripheral(DMA1, DMA_CHANNEL2); dma_enable_channel(DMA1, DMA_CHANNEL2); /* The SPI peripheral is driven by transmitted bytes, so dummy bytes * must be sent in order to receive data. This is accomplished with DMA * by simply not incrementing the memory address. */ dma_channel_reset(DMA1, DMA_CHANNEL3); dma_disable_channel(DMA1, DMA_CHANNEL3); dma_set_peripheral_address(DMA1, DMA_CHANNEL3, (uint32_t) &(SPI_DR(SPI3))); dma_set_memory_address(DMA1, DMA_CHANNEL3, (uint32_t) &RxSpiDummyByte); dma_set_number_of_data(DMA1, DMA_CHANNEL3, size); dma_set_priority(DMA1, DMA_CHANNEL3, DMA_CCR_PL_HIGH); dma_set_memory_size(DMA1, DMA_CHANNEL3, DMA_CCR_MSIZE_8BIT); dma_set_peripheral_size(DMA1, DMA_CHANNEL3, DMA_CCR_PSIZE_8BIT); dma_disable_memory_increment_mode(DMA1, DMA_CHANNEL3); dma_disable_peripheral_increment_mode(DMA1, DMA_CHANNEL3); dma_set_read_from_memory(DMA1, DMA_CHANNEL3); dma_enable_channel(DMA1, DMA_CHANNEL3); spi_enable_tx_dma(SPI3); spi_enable(SPI3); DmaCleanupNeeded = true; }
/* Cleanup between DMA transfers. */ static void cleanup_dma_spi(void){ /* Disable SPI without resetting the peripheral. */ dma_disable_channel(DMA1, DMA_CHANNEL3); dma_disable_channel(DMA1, DMA_CHANNEL2); spi_disable(SPI3); if(TxSpi){ /* After tx_spi() completes there will be several nonsense bytes * in the RXFIFO. They must be cleared out so that they don't * corrupt a subsequent SPI read. */ uint8_t throwaway; throwaway = SPI_DR(SPI3); throwaway = SPI_DR(SPI3); throwaway = SPI_DR(SPI3); throwaway = SPI_DR(SPI3); throwaway = throwaway; /* Suppress compiler warnings. */ TxSpi = false; } spi_disable_tx_dma(SPI3); spi_disable_rx_dma(SPI3); DmaCleanupNeeded = false; }
static void spi_dma_setup_rx(uint32_t spi, uint32_t dma, u8 stream, u8 channel) { spi_enable_rx_dma(spi); /* Make sure stream is disabled to start. */ DMA_SCR(dma, stream) &= ~DMA_SxCR_EN; /* RM0090 - 9.3.17 : Supposed to wait until enable bit reads '0' before we * write to registers. */ while (DMA_SCR(dma, stream) & DMA_SxCR_EN) ; /* RM0090 - 9.3.17 : Supposed to clear any interrupts in DMA status register * before we reconfigure registers. */ dma_clear_interrupt_flags(dma, stream, DMA_ISR_FLAGS); /* Configure the DMA controller. */ DMA_SCR(dma, stream) = 0; DMA_SCR(dma, stream) = /* Error interrupts. */ DMA_SxCR_DMEIE | DMA_SxCR_TEIE | DMA_SxCR_DIR_PERIPHERAL_TO_MEM | /* Enable DMA transfer complete interrupt */ DMA_SxCR_TCIE | /* Increment the memory address after each transfer. */ DMA_SxCR_MINC | /* 8 bit transfers from SPI peripheral. */ DMA_SxCR_PSIZE_8BIT | /* and to memory. */ DMA_SxCR_MSIZE_8BIT | /* Low priority. */ DMA_SxCR_PL_VERY_HIGH | /* The channel selects which request line will trigger a transfer. * (see CD00225773.pdf Table 23). */ DMA_SxCR_CHSEL(channel); /* Transfer up to the length of the buffer. */ DMA_SNDTR(dma, stream) = 0; /* DMA from the SPI data register... */ DMA_SPAR(dma, stream) = &SPI_DR(spi); /* Enable DMA interrupts for this stream with the NVIC. */ if (dma == DMA1) nvicEnableVector(dma_irq_lookup[0][stream], CORTEX_PRIORITY_MASK(CORTEX_MAX_KERNEL_PRIORITY+2)); else if (dma == DMA2) nvicEnableVector(dma_irq_lookup[1][stream], CORTEX_PRIORITY_MASK(CORTEX_MAX_KERNEL_PRIORITY+2)); }
/* Simultaneously transmit and receive data using DMA. */ void rxtx_spi(void *rxdata, const void *txdata, uint16_t size){ if(DmaCleanupNeeded)cleanup_dma_spi(); spi_enable_rx_dma(SPI3); dma_channel_reset(DMA1, DMA_CHANNEL2); dma_disable_channel(DMA1, DMA_CHANNEL2); dma_set_peripheral_address(DMA1, DMA_CHANNEL2, (uint32_t) &(SPI_DR(SPI3))); dma_set_memory_address(DMA1, DMA_CHANNEL2, (uint32_t) rxdata); dma_set_number_of_data(DMA1, DMA_CHANNEL2, size); dma_set_priority(DMA1, DMA_CHANNEL2, DMA_CCR_PL_HIGH); dma_set_memory_size(DMA1, DMA_CHANNEL2, DMA_CCR_MSIZE_8BIT); dma_set_peripheral_size(DMA1, DMA_CHANNEL2, DMA_CCR_PSIZE_8BIT); dma_enable_memory_increment_mode(DMA1, DMA_CHANNEL2); dma_disable_peripheral_increment_mode(DMA1, DMA_CHANNEL2); dma_set_read_from_peripheral(DMA1, DMA_CHANNEL2); dma_enable_channel(DMA1, DMA_CHANNEL2); dma_channel_reset(DMA1, DMA_CHANNEL3); dma_disable_channel(DMA1, DMA_CHANNEL3); dma_set_peripheral_address(DMA1, DMA_CHANNEL3, (uint32_t) &(SPI_DR(SPI3))); dma_set_memory_address(DMA1, DMA_CHANNEL3, (uint32_t) txdata); dma_set_number_of_data(DMA1, DMA_CHANNEL3, size); dma_set_priority(DMA1, DMA_CHANNEL3, DMA_CCR_PL_HIGH); dma_set_memory_size(DMA1, DMA_CHANNEL3, DMA_CCR_MSIZE_8BIT); dma_set_peripheral_size(DMA1, DMA_CHANNEL3, DMA_CCR_PSIZE_8BIT); dma_enable_memory_increment_mode(DMA1, DMA_CHANNEL3); dma_disable_peripheral_increment_mode(DMA1, DMA_CHANNEL3); dma_set_read_from_memory(DMA1, DMA_CHANNEL3); dma_enable_channel(DMA1, DMA_CHANNEL3); spi_enable_tx_dma(SPI3); spi_enable(SPI3); DmaCleanupNeeded = true; }
uint16_t spi_clean_disable(uint32_t spi) { /* Wait to receive last data */ while (!(SPI_SR(spi) & SPI_SR_RXNE)); uint16_t data = SPI_DR(spi); /* Wait to transmit last data */ while (!(SPI_SR(spi) & SPI_SR_TXE)); /* Wait until not busy */ while (SPI_SR(spi) & SPI_SR_BSY); SPI_CR1(spi) &= ~SPI_CR1_SPE; return data; }
void acq_init() { /* Initialize amplifier control GPIO */ gpio_mode_setup(BANK_AMP, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_AMP); gpio_clear(BANK_AMP, GPIO_AMP); gpio_mode_setup(BANK_LED, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_LED); gpio_clear(BANK_LED, GPIO_LED); /* Initialize SPI GPIOs */ gpio_mode_setup(BANK_CS, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_CS); gpio_mode_setup(BANK_SCLK, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_SCLK); gpio_mode_setup(BANK_DOUT, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_DOUT); gpio_set_af(BANK_CS, GPIO_AF6, GPIO_CS); gpio_set_af(BANK_SCLK, GPIO_AF6, GPIO_SCLK); gpio_set_af(BANK_DOUT, GPIO_AF6, GPIO_DOUT); rcc_periph_clock_enable(RCC_SPI3); acq_spi_init(SPI_C1); rcc_periph_clock_enable(RCC_DMA1); dma_channel_reset(DMA1, DMA_CHANNEL2); dma_disable_channel(DMA1, DMA_CHANNEL2); dma_set_peripheral_address(DMA1, DMA_CHANNEL2, (uint32_t)&SPI_DR(SPI_C1)); dma_set_memory_address(DMA1, DMA_CHANNEL2, (uint32_t)&acq_channel.buff); dma_set_number_of_data(DMA1, DMA_CHANNEL2, BUFFER_SIZE); dma_set_priority(DMA1, DMA_CHANNEL2, DMA_CCR_PL_MEDIUM); dma_set_memory_size(DMA1, DMA_CHANNEL2, DMA_CCR_MSIZE_16BIT); dma_set_peripheral_size(DMA1, DMA_CHANNEL2, DMA_CCR_PSIZE_16BIT); dma_enable_memory_increment_mode(DMA1, DMA_CHANNEL2); dma_set_read_from_peripheral(DMA1, DMA_CHANNEL2); dma_enable_circular_mode(DMA1, DMA_CHANNEL2); nvic_set_priority(NVIC_DMA1_CHANNEL2_IRQ, PRIO_ACQ); }
static void spi_dma_setup_tx(uint32_t spi, uint32_t dma, u8 stream, u8 channel) { spi_enable_tx_dma(spi); /* Make sure stream is disabled to start. */ DMA_SCR(dma, stream) &= ~DMA_SxCR_EN; /* Configure the DMA controller. */ DMA_SCR(dma, stream) = 0; DMA_SCR(dma, stream) = /* Error interrupts. */ DMA_SxCR_DMEIE | DMA_SxCR_TEIE | DMA_SxCR_DIR_MEM_TO_PERIPHERAL | /* Increment the memory address after each transfer. */ DMA_SxCR_MINC | /* 8 bit transfers from SPI peripheral. */ DMA_SxCR_PSIZE_8BIT | /* and to memory. */ DMA_SxCR_MSIZE_8BIT | /* Low priority. */ DMA_SxCR_PL_VERY_HIGH | /* The channel selects which request line will trigger a transfer. * (see CD00225773.pdf Table 23). */ DMA_SxCR_CHSEL(channel); /* Transfer up to the length of the buffer. */ DMA_SNDTR(dma, stream) = 0; /* DMA from the SPI data register... */ DMA_SPAR(dma, stream) = &SPI_DR(spi); /* Enable DMA interrupts for this stream with the NVIC. */ if (dma == DMA1) nvicEnableVector(dma_irq_lookup[0][stream], CORTEX_PRIORITY_MASK(CORTEX_MAX_KERNEL_PRIORITY+2)); else if (dma == DMA2) nvicEnableVector(dma_irq_lookup[1][stream], CORTEX_PRIORITY_MASK(CORTEX_MAX_KERNEL_PRIORITY+2)); }
void codecInit(void) { memset(adcBuffer, 0xaa, sizeof(adcBuffer)); // I2S2 alternate function mapping gpio_mode_setup(GPIOB, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO12 | GPIO13 | GPIO14 | GPIO15); gpio_set_af(GPIOB, GPIO_AF5, GPIO12 | GPIO13 | GPIO15); gpio_set_af(GPIOB, GPIO_AF6, GPIO14); // I2S2ext_SD (I2S receive) gpio_mode_setup(GPIOC, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO6); gpio_set_af(GPIOC, GPIO_AF5, GPIO6); // MCLK gpio_set_output_options(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_25MHZ, GPIO12 | GPIO13 | GPIO15); gpio_set_output_options(GPIOC, GPIO_OTYPE_PP, GPIO_OSPEED_100MHZ, GPIO6); // Set up SPI1 spi_reset(SPI1); spi_init_master(SPI1, SPI_CR1_BAUDRATE_FPCLK_DIV_256, SPI_CR1_CPOL_CLK_TO_1_WHEN_IDLE, SPI_CR1_CPHA_CLK_TRANSITION_2, SPI_CR1_DFF_16BIT, SPI_CR1_MSBFIRST); spi_set_nss_high(SPI1); spi_enable_software_slave_management(SPI1); spi_enable(SPI1); // SPI1 alternate function mapping, set CSB signal high output gpio_mode_setup(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO5 | GPIO7); gpio_set_af(GPIOA, GPIO_AF5, GPIO5 | GPIO7); gpio_set(GPIOA, GPIO4); gpio_mode_setup(GPIOA, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO4); codecConfig(); // Set up I2S for 48kHz 16-bit stereo. // The input to the PLLI2S is 1MHz. Division factors are from // table 126 in the data sheet. // // This gives us 1.536MHz SCLK = 16 bits * 2 channels * 48000 Hz // and 12.288 MHz MCLK = 256 * 48000 Hz. // With this PLL configuration the actual sampling frequency // is nominally 47991 Hz. spi_reset(SPI2); RCC_PLLI2SCFGR = (3 << 28) | (258 << 6); RCC_CR |= RCC_CR_PLLI2SON; while (!(RCC_CR & RCC_CR_PLLI2SRDY)); const unsigned i2sdiv = 3; SPI_I2SPR(SPI2) = SPI_I2SPR_MCKOE | SPI_I2SPR_ODD | i2sdiv; SPI_I2SCFGR(SPI2) |= SPI_I2SCFGR_I2SMOD | SPI_I2SCFGR_I2SE | (SPI_I2SCFGR_I2SCFG_MASTER_TRANSMIT << SPI_I2SCFGR_I2SCFG_LSB); SPI_I2SCFGR(I2S2_EXT_BASE) = SPI_I2SCFGR_I2SMOD | SPI_I2SCFGR_I2SE | (SPI_I2SCFGR_I2SCFG_SLAVE_RECEIVE << SPI_I2SCFGR_I2SCFG_LSB); // Configure the DMA engine to stream data to the DAC. dma_stream_reset(DMA1, DAC_DMA_STREAM); dma_set_peripheral_address(DMA1, DAC_DMA_STREAM, (intptr_t)&SPI_DR(SPI2)); dma_set_memory_address(DMA1, DAC_DMA_STREAM, (intptr_t)dacBuffer[0]); dma_set_memory_address_1(DMA1, DAC_DMA_STREAM, (intptr_t)dacBuffer[1]); dma_set_number_of_data(DMA1, DAC_DMA_STREAM, BUFFER_SAMPLES); dma_channel_select(DMA1, DAC_DMA_STREAM, DAC_DMA_CHANNEL); dma_set_transfer_mode(DMA1, DAC_DMA_STREAM, DMA_SxCR_DIR_MEM_TO_PERIPHERAL); dma_set_memory_size(DMA1, DAC_DMA_STREAM, DMA_SxCR_MSIZE_16BIT); dma_set_peripheral_size(DMA1, DAC_DMA_STREAM, DMA_SxCR_PSIZE_16BIT); dma_enable_memory_increment_mode(DMA1, DAC_DMA_STREAM); dma_enable_double_buffer_mode(DMA1, DAC_DMA_STREAM); dma_enable_stream(DMA1, DAC_DMA_STREAM); // Configure the DMA engine to stream data from the ADC. dma_stream_reset(DMA1, ADC_DMA_STREAM); dma_set_peripheral_address(DMA1, ADC_DMA_STREAM, (intptr_t)&SPI_DR(I2S2_EXT_BASE)); dma_set_memory_address(DMA1, ADC_DMA_STREAM, (intptr_t)adcBuffer[0]); dma_set_memory_address_1(DMA1, ADC_DMA_STREAM, (intptr_t)adcBuffer[1]); dma_set_number_of_data(DMA1, ADC_DMA_STREAM, BUFFER_SAMPLES); dma_channel_select(DMA1, ADC_DMA_STREAM, ADC_DMA_CHANNEL); dma_set_transfer_mode(DMA1, ADC_DMA_STREAM, DMA_SxCR_DIR_PERIPHERAL_TO_MEM); dma_set_memory_size(DMA1, ADC_DMA_STREAM, DMA_SxCR_MSIZE_16BIT); dma_set_peripheral_size(DMA1, ADC_DMA_STREAM, DMA_SxCR_PSIZE_16BIT); dma_enable_memory_increment_mode(DMA1, ADC_DMA_STREAM); dma_enable_double_buffer_mode(DMA1, ADC_DMA_STREAM); dma_enable_stream(DMA1, ADC_DMA_STREAM); dma_enable_transfer_complete_interrupt(DMA1, ADC_DMA_STREAM); nvic_enable_irq(NVIC_DMA1_STREAM3_IRQ); nvic_set_priority(NVIC_DMA1_STREAM3_IRQ, 0x80); // 0 is most urgent // Start transmitting data spi_enable_rx_dma(I2S2_EXT_BASE); spi_enable_tx_dma(SPI2); }
static int spi_dma_transceive(uint8_t *tx_buf, int tx_len, uint8_t *rx_buf, int rx_len) #endif { /* Check for 0 length in both tx and rx */ if ((rx_len < 1) && (tx_len < 1)) { /* return -1 as error */ return -1; } /* Reset DMA channels*/ dma_channel_reset(DMA1, DMA_CHANNEL4); dma_channel_reset(DMA1, DMA_CHANNEL5); /* Reset SPI data and status registers. * Here we assume that the SPI peripheral is NOT * busy any longer, i.e. the last activity was verified * complete elsewhere in the program. */ volatile uint8_t temp_data __attribute__ ((unused)); while (SPI_SR(SPI2) & (SPI_SR_RXNE | SPI_SR_OVR)) { temp_data = SPI_DR(SPI2); } /* Reset status flag appropriately (both 0 case caught above) */ transceive_status = NONE; if (rx_len < 1) { transceive_status = ONE; } if (tx_len < 1) { transceive_status = ONE; } /* Set up rx dma, note it has higher priority to avoid overrun */ if (rx_len > 0) { dma_set_peripheral_address(DMA1, DMA_CHANNEL4, (uint32_t)&SPI2_DR); dma_set_memory_address(DMA1, DMA_CHANNEL4, (uint32_t)rx_buf); dma_set_number_of_data(DMA1, DMA_CHANNEL4, rx_len); dma_set_read_from_peripheral(DMA1, DMA_CHANNEL4); dma_enable_memory_increment_mode(DMA1, DMA_CHANNEL4); #if USE_16BIT_TRANSFERS dma_set_peripheral_size(DMA1, DMA_CHANNEL4, DMA_CCR_PSIZE_16BIT); dma_set_memory_size(DMA1, DMA_CHANNEL4, DMA_CCR_MSIZE_16BIT); #else dma_set_peripheral_size(DMA1, DMA_CHANNEL4, DMA_CCR_PSIZE_8BIT); dma_set_memory_size(DMA1, DMA_CHANNEL4, DMA_CCR_MSIZE_8BIT); #endif dma_set_priority(DMA1, DMA_CHANNEL4, DMA_CCR_PL_VERY_HIGH); } /* Set up tx dma */ if (tx_len > 0) { dma_set_peripheral_address(DMA1, DMA_CHANNEL5, (uint32_t)&SPI2_DR); dma_set_memory_address(DMA1, DMA_CHANNEL5, (uint32_t)tx_buf); dma_set_number_of_data(DMA1, DMA_CHANNEL5, tx_len); dma_set_read_from_memory(DMA1, DMA_CHANNEL5); dma_enable_memory_increment_mode(DMA1, DMA_CHANNEL5); #if USE_16BIT_TRANSFERS dma_set_peripheral_size(DMA1, DMA_CHANNEL5, DMA_CCR_PSIZE_16BIT); dma_set_memory_size(DMA1, DMA_CHANNEL5, DMA_CCR_MSIZE_16BIT); #else dma_set_peripheral_size(DMA1, DMA_CHANNEL5, DMA_CCR_PSIZE_8BIT); dma_set_memory_size(DMA1, DMA_CHANNEL5, DMA_CCR_MSIZE_8BIT); #endif dma_set_priority(DMA1, DMA_CHANNEL5, DMA_CCR_PL_HIGH); } /* Enable dma transfer complete interrupts */ if (rx_len > 0) { dma_enable_transfer_complete_interrupt(DMA1, DMA_CHANNEL4); } if (tx_len > 0) { dma_enable_transfer_complete_interrupt(DMA1, DMA_CHANNEL5); } /* Activate dma channels */ if (rx_len > 0) { dma_enable_channel(DMA1, DMA_CHANNEL4); } if (tx_len > 0) { dma_enable_channel(DMA1, DMA_CHANNEL5); } /* Enable the spi transfer via dma * This will immediately start the transmission, * after which when the receive is complete, the * receive dma will activate */ if (rx_len > 0) { spi_enable_rx_dma(SPI2); } if (tx_len > 0) { spi_enable_tx_dma(SPI2); } return 0; }
/***************************************************************************** * 函 数 名 : spiSend * * 功能描述 : SPI数据轮询发送 * * 输入参数 : spiNo SPI控制器号 * cs: 片选号 * pData: 指向要发送数据地址的指针 * ulLen:要发送的数据的大小 * 输出参数 : * * 返 回 值 : OK or ERROR * * 其它说明 : * *****************************************************************************/ s32 spi_send (u32 spiNo, u32 cs, u16* pData, u32 ulLen) { u16 *pSh; u32 i; u32 ulLoop = SPI_MAX_DELAY_TIMES; u32 ulVal; if (((0 != spiNo) && (1 != spiNo)) || (0 != cs && 1 != cs) || (NULL == pData) || (0 == ulLen)) { return ERROR; } pSh = (u16*)pData; /* 禁止SPI Slave*/ writel(0, SPI_SLAVE_EN(spiNo)); /* 禁止SPI Master*/ writel(0, SPI_EN(spiNo)); /* 设置成发送模式 */ writel(((readl(SPI_CTRL0(spiNo)) & ~SPI_CTRL0_TMOD_BITMASK) | SPI_CTRL0_TMOD_SEND),SPI_CTRL0(spiNo)); /*使能SPI Master*/ writel(1, SPI_EN(spiNo)); /*使能SPI Slave*/ writel((1 << cs), SPI_SLAVE_EN(spiNo)); /* 发送命令 */ for(i = 0; i < ulLen; i++) { /* 等待发送FIFO非满 */ while(!(readl(SPI_STATUS(spiNo)) & SPI_STATUS_TXNOTFULL) && (0 != --ulLoop)) { } if(0 == ulLoop) { return ERROR; } writel(*pSh++, SPI_DR(spiNo)); } /*将发送FIFO中的数据全部发出,且不BUSY*/ ulLoop = SPI_MAX_DELAY_TIMES; ulVal = readl(SPI_STATUS(spiNo)); while(((!(ulVal & SPI_STATUS_TXEMPTY)) || (ulVal & SPI_STATUS_BUSY)) && (0 != --ulLoop)) { ulVal = readl(SPI_STATUS(spiNo)); } if(0 == ulLoop) { return ERROR; } return OK; }
/***************************************************************************** * 函 数 名 : spiRecv * * 功能描述 : SPI数据轮询接收数据 * * 输入参数 : spiNo SPI控制器号 * cs: 片选号 * prevData: 指向要读取数据地址的指针 * recvSize:要读取的数据的大小 * psendData: 指向要发送的命令和地址的指针 * sendSize: 要发送命令和地址的长度(3 或者4) * 输出参数 : * * 返 回 值 : OK or ERROR * * 其它说明 : * *****************************************************************************/ s32 spi_recv (u32 spiNo, u32 cs, u16* prevData, u32 recvSize,u16* psendData,u32 sendSize ) { u16 *pRh; u16 *pSh; u32 i; u32 ulLoop = SPI_MAX_DELAY_TIMES; /*有2个spi控制器,每个控制器有2个片选*/ if (((0 != spiNo) && (1 != spiNo)) || (0 != cs && 1 != cs) || (NULL == psendData) || (NULL == prevData) || (0 == recvSize) || (0 == sendSize)) { return ERROR; } pRh = prevData; pSh = psendData; /* 禁止SPI Slave*/ writel(0,SPI_SLAVE_EN(spiNo)); /* 禁止SPI Master*/ writel(0, SPI_EN(spiNo)); /* 设置成EEPROM读模式 */ /*writel((readl(SPI_CTRL0(spiNo)) | SPI_CTRL0_TMOD_EEPROM_READ),SPI_CTRL0(spiNo));*/ writel(((readl(SPI_CTRL0(spiNo)) & ~SPI_CTRL0_TMOD_BITMASK) | SPI_CTRL0_TMOD_SEND_RECV),SPI_CTRL0(spiNo)); /* 设置接收数据的数目*/ writel((recvSize-1),SPI_CTRL1(spiNo)); /*使能SPI Master*/ writel(1, SPI_EN(spiNo)); /*使能SPI Slave*/ writel((1 << cs), SPI_SLAVE_EN(spiNo)); /* 发送命令 */ for(i = 0; i < sendSize; i++) { /* 等待发送FIFO非满 */ while(!(readl(SPI_STATUS(spiNo)) & SPI_STATUS_TXNOTFULL) && (0 != --ulLoop)) { } if(0 == ulLoop) { return ERROR; } writel(*pSh++, SPI_DR(spiNo)); } /*将发送FIFO中的数据全部发出*/ while(!(readl(SPI_STATUS(spiNo)) & SPI_STATUS_TXEMPTY) && (0 != --ulLoop)) { } if(0 == ulLoop) { return ERROR; } /* 接收数据 */ for(i = 0; i < recvSize; i++) { ulLoop = SPI_MAX_DELAY_TIMES; /* 等待读取到数据 */ while(!(readl(SPI_STATUS(spiNo)) & SPI_STATUS_RXNOTEMPTY) && (0 != --ulLoop)) { } if(0 == ulLoop) { return ERROR; } *pRh++ = readl(SPI_DR(spiNo)); } /* SPI控制器会自动禁使能,这里无需软件操作 */ #if 0 /* 禁止SPI Slave*/ writel(0, SPI_SLAVE_EN(spiNo)); /* 禁止SPI Master*/ writel(0, SPI_EN(spiNo)); #endif return OK; }
bool TSpiDmaQueue::TryStartJob() { // Start the next DMA job in the queue if the SPI interface is // available (TXE=1 and BSY=0) // We treat both SPI busses (flash and display) as one, so no concurrent jobs // are allowed. const uint32_t spi = LCD_SPI_CHANNEL; if ((SPI_SR(spi) & SPI_SR_TXE) && (~SPI_SR(spi) & SPI_SR_BSY)) { if (Jobs.Empty()) { return false; } const TSpiDmaJob& job = Jobs.First(); const TBuffer& buffer = job.GetBuffer(); // SPI receive register should be empty here! assert(!(SPI_SR(spi) & SPI_SR_RXNE)); const uint32_t dma = DMA1; { const uint32_t channel = (job.GetChip() == TSpiDmaJob::CS_LCD) ? LCD_DMA_TX_CHANNEL : FLASH_DMA_TX_CHANNEL; dma_channel_reset(dma, channel); dma_set_peripheral_address(dma, channel, reinterpret_cast<uint32_t>(&SPI_DR(spi))); dma_set_memory_address(dma, channel, reinterpret_cast<uint32_t>(buffer.GetData())); dma_set_number_of_data(dma, channel, buffer.GetLength()); dma_set_read_from_memory(dma, channel); dma_enable_memory_increment_mode(dma, channel); dma_set_peripheral_size(dma, channel, DMA_CCR_PSIZE_8BIT); dma_set_memory_size(dma, channel, DMA_CCR_MSIZE_8BIT); dma_set_priority(dma, channel, DMA_CCR_PL_LOW); //dma_enable_transfer_complete_interrupt(dma, channel); dma_enable_channel(dma, channel); } { const uint32_t channel = (job.GetChip() == TSpiDmaJob::CS_LCD) ? LCD_DMA_RX_CHANNEL : FLASH_DMA_RX_CHANNEL; dma_channel_reset(dma, channel); dma_set_peripheral_address(dma, channel, reinterpret_cast<uint32_t>(&SPI_DR(spi))); dma_set_memory_address(dma, channel, reinterpret_cast<uint32_t>(buffer.GetData())); dma_set_number_of_data(dma, channel, buffer.GetLength()); dma_enable_memory_increment_mode(dma, channel); dma_set_peripheral_size(dma, channel, DMA_CCR_PSIZE_8BIT); dma_set_memory_size(dma, channel, DMA_CCR_MSIZE_8BIT); dma_set_priority(dma, channel, DMA_CCR_PL_LOW); dma_enable_transfer_complete_interrupt(dma, channel); dma_enable_channel(dma, channel); } // Set CS and LCD_A0 lines Pin_lcd_cs.Clear(); if (job.GetLcdData()) { Pin_lcd_a0.Set(); } else { Pin_lcd_a0.Clear(); } // Kick off the transfer spi_enable_rx_dma(spi); spi_enable_tx_dma(spi); return true; } return false; }
u16 spi_recv(spi_t spi) { return SPI_DR(base_addr(spi)); }
void spi_send(spi_t spi, u16 data) { SPI_DR(base_addr(spi)) = data; }
static int spi_dma_transceive(uint8_t *tx_buf, int tx_len, uint8_t *rx_buf, int rx_len) #endif { /* Check for 0 length in both tx and rx */ if ((rx_len < 1) && (tx_len < 1)) { /* return -1 as error */ return -1; } /* Reset DMA channels*/ dma_channel_reset(DMA1, DMA_CHANNEL2); dma_channel_reset(DMA1, DMA_CHANNEL3); /* Reset SPI data and status registers. * Here we assume that the SPI peripheral is NOT * busy any longer, i.e. the last activity was verified * complete elsewhere in the program. */ volatile uint8_t temp_data __attribute__ ((unused)); while (SPI_SR(SPI1) & (SPI_SR_RXNE | SPI_SR_OVR)) { temp_data = SPI_DR(SPI1); } /* Reset status flag appropriately (both 0 case caught above) */ transceive_status = NONE; if (rx_len < 1) { transceive_status = ONE; } /* Determine tx length case to change behaviour * If tx_len >= rx_len, then normal case, run both DMAs with normal settings * If rx_len == 0, just don't run the rx DMA at all * If tx_len == 0, use a dummy buf and set the tx dma to transfer the same * amount as the rx_len, to ensure everything is clocked in * If 0 < tx_len < rx_len, first do a normal case, then on the tx finished * interrupt, set up a new dummyy buf tx dma transfer for the remaining * required clock cycles (handled in tx dma complete interrupt) */ if ((tx_len > 0) && (tx_len < rx_len)) { rx_buf_remainder = rx_len - tx_len; } /* Set up rx dma, note it has higher priority to avoid overrun */ if (rx_len > 0) { dma_set_peripheral_address(DMA1, DMA_CHANNEL2, (uint32_t)&SPI1_DR); dma_set_memory_address(DMA1, DMA_CHANNEL2, (uint32_t)rx_buf); dma_set_number_of_data(DMA1, DMA_CHANNEL2, rx_len); dma_set_read_from_peripheral(DMA1, DMA_CHANNEL2); dma_enable_memory_increment_mode(DMA1, DMA_CHANNEL2); #if USE_16BIT_TRANSFERS dma_set_peripheral_size(DMA1, DMA_CHANNEL2, DMA_CCR_PSIZE_16BIT); dma_set_memory_size(DMA1, DMA_CHANNEL2, DMA_CCR_MSIZE_16BIT); #else dma_set_peripheral_size(DMA1, DMA_CHANNEL2, DMA_CCR_PSIZE_8BIT); dma_set_memory_size(DMA1, DMA_CHANNEL2, DMA_CCR_MSIZE_8BIT); #endif dma_set_priority(DMA1, DMA_CHANNEL2, DMA_CCR_PL_VERY_HIGH); } /* Set up tx dma (must always run tx to get clock signal) */ if (tx_len > 0) { /* Here we have a regular tx transfer */ dma_set_peripheral_address(DMA1, DMA_CHANNEL3, (uint32_t)&SPI1_DR); dma_set_memory_address(DMA1, DMA_CHANNEL3, (uint32_t)tx_buf); dma_set_number_of_data(DMA1, DMA_CHANNEL3, tx_len); dma_set_read_from_memory(DMA1, DMA_CHANNEL3); dma_enable_memory_increment_mode(DMA1, DMA_CHANNEL3); #if USE_16BIT_TRANSFERS dma_set_peripheral_size(DMA1, DMA_CHANNEL3, DMA_CCR_PSIZE_16BIT); dma_set_memory_size(DMA1, DMA_CHANNEL3, DMA_CCR_MSIZE_16BIT); #else dma_set_peripheral_size(DMA1, DMA_CHANNEL3, DMA_CCR_PSIZE_8BIT); dma_set_memory_size(DMA1, DMA_CHANNEL3, DMA_CCR_MSIZE_8BIT); #endif dma_set_priority(DMA1, DMA_CHANNEL3, DMA_CCR_PL_HIGH); } else { /* Here we aren't transmitting any real data, use the dummy buffer * and set the length to the rx_len to get all rx data in, while * not incrementing the memory pointer */ dma_set_peripheral_address(DMA1, DMA_CHANNEL3, (uint32_t)&SPI1_DR); dma_set_memory_address(DMA1, DMA_CHANNEL3, (uint32_t)(&dummy_tx_buf)); // Change here dma_set_number_of_data(DMA1, DMA_CHANNEL3, rx_len); // Change here dma_set_read_from_memory(DMA1, DMA_CHANNEL3); dma_disable_memory_increment_mode(DMA1, DMA_CHANNEL3); // Change here #if USE_16BIT_TRANSFERS dma_set_peripheral_size(DMA1, DMA_CHANNEL3, DMA_CCR_PSIZE_16BIT); dma_set_memory_size(DMA1, DMA_CHANNEL3, DMA_CCR_MSIZE_16BIT); #else dma_set_peripheral_size(DMA1, DMA_CHANNEL3, DMA_CCR_PSIZE_8BIT); dma_set_memory_size(DMA1, DMA_CHANNEL3, DMA_CCR_MSIZE_8BIT); #endif dma_set_priority(DMA1, DMA_CHANNEL3, DMA_CCR_PL_HIGH); } /* Enable dma transfer complete interrupts */ if (rx_len > 0) { dma_enable_transfer_complete_interrupt(DMA1, DMA_CHANNEL2); } dma_enable_transfer_complete_interrupt(DMA1, DMA_CHANNEL3); /* Activate dma channels */ if (rx_len > 0) { dma_enable_channel(DMA1, DMA_CHANNEL2); } dma_enable_channel(DMA1, DMA_CHANNEL3); /* Enable the spi transfer via dma * This will immediately start the transmission, * after which when the receive is complete, the * receive dma will activate */ if (rx_len > 0) { spi_enable_rx_dma(SPI1); } spi_enable_tx_dma(SPI1); return 0; }
void spi_write(uint32_t spi, uint16_t data) { /* Write data (8 or 16 bits, depending on DFF) into DR. */ SPI_DR(spi) = data; }