kopia lustrzana https://github.com/Jean-MarcHarvengt/MCUME
162 wiersze
6.4 KiB
C
Executable File
162 wiersze
6.4 KiB
C
Executable File
/* ========================================
|
|
*
|
|
* Copyright YOUR COMPANY, THE YEAR
|
|
* All Rights Reserved
|
|
* UNPUBLISHED, LICENSED SOFTWARE.
|
|
*
|
|
* CONFIDENTIAL AND PROPRIETARY INFORMATION
|
|
* WHICH IS THE PROPERTY OF your company.
|
|
*
|
|
* ========================================
|
|
*/
|
|
#include <stdbool.h>
|
|
//
|
|
#include "pico/stdlib.h"
|
|
#include "pico/sem.h"
|
|
//
|
|
#include "my_debug.h"
|
|
//
|
|
#include "spi.h"
|
|
|
|
void spi_irq_handler(spi_t *this) {
|
|
// Clear the interrupt request.
|
|
dma_hw->ints0 = 1u << this->rx_dma;
|
|
myASSERT(!dma_channel_is_busy(this->rx_dma));
|
|
sem_release(&this->sem);
|
|
}
|
|
|
|
// SPI Transfer: Read & Write (simultaneously) on SPI bus
|
|
// If the data that will be received is not important, pass NULL as rx.
|
|
// If the data that will be transmitted is not important,
|
|
// pass NULL as tx and then the SPI_FILL_CHAR is sent out as each data
|
|
// element.
|
|
|
|
bool spi_transfer(spi_t *this, const uint8_t *tx, uint8_t *rx, size_t length) {
|
|
myASSERT(512 == length);
|
|
myASSERT(tx || rx);
|
|
// myASSERT(!(tx && rx));
|
|
|
|
// tx write increment is already false
|
|
if (tx) {
|
|
channel_config_set_read_increment(&this->tx_dma_cfg, true);
|
|
} else {
|
|
static const uint8_t dummy = SPI_FILL_CHAR;
|
|
tx = &dummy;
|
|
channel_config_set_read_increment(&this->tx_dma_cfg, false);
|
|
}
|
|
// rx read increment is already false
|
|
if (rx) {
|
|
channel_config_set_write_increment(&this->rx_dma_cfg, true);
|
|
} else {
|
|
static uint8_t dummy = 0xA5;
|
|
rx = &dummy;
|
|
channel_config_set_write_increment(&this->rx_dma_cfg, false);
|
|
}
|
|
// Clear the interrupt request.
|
|
dma_hw->ints0 = 1u << this->rx_dma;
|
|
|
|
dma_channel_configure(this->tx_dma, &this->tx_dma_cfg,
|
|
&spi_get_hw(this->hw_inst)->dr, // write address
|
|
tx, // read address
|
|
XFER_BLOCK_SIZE, // element count (each element is of
|
|
// size transfer_data_size)
|
|
false); // start
|
|
dma_channel_configure(this->rx_dma, &this->rx_dma_cfg,
|
|
rx, // write address
|
|
&spi_get_hw(this->hw_inst)->dr, // read address
|
|
XFER_BLOCK_SIZE, // element count (each element is of
|
|
// size transfer_data_size)
|
|
false); // start
|
|
|
|
// start them exactly simultaneously to avoid races (in extreme cases
|
|
// the FIFO could overflow)
|
|
dma_start_channel_mask((1u << this->tx_dma) | (1u << this->rx_dma));
|
|
|
|
/* Timeout 1 sec */
|
|
uint32_t timeOut = 1000;
|
|
/* Wait until master completes transfer or time out has occured. */
|
|
bool rc = sem_acquire_timeout_ms(&this->sem, timeOut); // Wait for notification from ISR
|
|
if (!rc) {
|
|
// If the timeout is reached the function will return false
|
|
DBG_PRINTF("Notification wait timed out in %s\n", __FUNCTION__);
|
|
return false;
|
|
}
|
|
dma_channel_wait_for_finish_blocking(this->tx_dma);
|
|
dma_channel_wait_for_finish_blocking(this->rx_dma);
|
|
|
|
myASSERT(!dma_channel_is_busy(this->tx_dma));
|
|
myASSERT(!dma_channel_is_busy(this->rx_dma));
|
|
|
|
return true;
|
|
}
|
|
|
|
bool my_spi_init(spi_t *this) {
|
|
// bool __atomic_test_and_set (void *ptr, int memorder)
|
|
// This built-in function performs an atomic test-and-set operation on the
|
|
// byte at *ptr. The byte is set to some implementation defined nonzero
|
|
// “set” value and the return value is true if and only if the previous
|
|
// contents were “set”.
|
|
if (__atomic_test_and_set(&(this->initialized), __ATOMIC_SEQ_CST))
|
|
return true;
|
|
|
|
// The SPI may be shared (using multiple SSs); protect it
|
|
sem_init(&this->sem, 0, 1);
|
|
/* Configure component */
|
|
// Enable SPI at 100 kHz and connect to GPIOs
|
|
spi_init(this->hw_inst, 100 * 1000);
|
|
spi_set_format(this->hw_inst, 8, SPI_CPOL_0, SPI_CPHA_0, SPI_MSB_FIRST);
|
|
|
|
gpio_set_function(this->miso_gpio, GPIO_FUNC_SPI);
|
|
gpio_set_function(this->mosi_gpio, GPIO_FUNC_SPI);
|
|
gpio_set_function(this->sck_gpio, GPIO_FUNC_SPI);
|
|
// ss_gpio is initialized in sd_spi_init()
|
|
|
|
// SD cards' DO MUST be pulled up.
|
|
gpio_pull_up(this->miso_gpio);
|
|
// Grab some unused dma channels
|
|
this->tx_dma = dma_claim_unused_channel(true);
|
|
this->rx_dma = dma_claim_unused_channel(true);
|
|
|
|
|
|
this->tx_dma_cfg = dma_channel_get_default_config(this->tx_dma);
|
|
this->rx_dma_cfg = dma_channel_get_default_config(this->rx_dma);
|
|
channel_config_set_transfer_data_size(&this->tx_dma_cfg, DMA_SIZE_8);
|
|
channel_config_set_transfer_data_size(&this->rx_dma_cfg, DMA_SIZE_8);
|
|
|
|
|
|
|
|
// We set the outbound DMA to transfer from a memory buffer to the SPI
|
|
// transmit FIFO paced by the SPI TX FIFO DREQ The default is for the
|
|
// read address to increment every element (in this case 1 byte -
|
|
// DMA_SIZE_8) and for the write address to remain unchanged.
|
|
channel_config_set_dreq(&this->tx_dma_cfg, spi_get_index(this->hw_inst)
|
|
? DREQ_SPI1_TX
|
|
: DREQ_SPI0_TX);
|
|
channel_config_set_write_increment(&this->tx_dma_cfg, false);
|
|
|
|
// We set the inbound DMA to transfer from the SPI receive FIFO to a
|
|
// memory buffer paced by the SPI RX FIFO DREQ We coinfigure the read
|
|
// address to remain unchanged for each element, but the write address
|
|
// to increment (so data is written throughout the buffer)
|
|
channel_config_set_dreq(&this->rx_dma_cfg, spi_get_index(this->hw_inst)
|
|
? DREQ_SPI1_RX
|
|
: DREQ_SPI0_RX);
|
|
channel_config_set_read_increment(&this->rx_dma_cfg, false);
|
|
|
|
/* Theory: we only need an interrupt on rx complete,
|
|
since if rx is complete, tx must also be complete. */
|
|
|
|
// Configure the processor to run dma_handler() when DMA IRQ 0 is
|
|
// asserted
|
|
irq_set_exclusive_handler(DMA_IRQ_1, this->dma_isr); // JMH
|
|
|
|
// Tell the DMA to raise IRQ line 0 when the channel finishes a block
|
|
dma_channel_set_irq1_enabled(this->rx_dma, true); // JMH
|
|
irq_set_enabled(DMA_IRQ_1, true); // JMH
|
|
|
|
LED_INIT();
|
|
return true;
|
|
}
|
|
|
|
/* [] END OF FILE */
|