I should have known that, I've done that before but when you're hacking and tweaking it's easily done.Ah yes. There are lots of idiosyncrasies that they don't tell you, such as you need to enable the peripheral clock for each module.
private void enable_clock_from_pin(uint64_t pin)
{
// Enable the GPIO clock for the pin
uint32_t base = (uint32_t)(DECODE_BASE(pin));
switch (base)
{
case GPIOA_BASE:
__GPIOA_CLK_ENABLE();
break;
case GPIOB_BASE:
__GPIOB_CLK_ENABLE();
break;
case GPIOC_BASE:
__GPIOC_CLK_ENABLE();
break;
case GPIOD_BASE:
__GPIOD_CLK_ENABLE();
break;
case GPIOE_BASE:
__GPIOE_CLK_ENABLE();
break;
case GPIOF_BASE:
__GPIOF_CLK_ENABLE();
break;
case GPIOG_BASE:
__GPIOG_CLK_ENABLE();
break;
case GPIOH_BASE:
__GPIOH_CLK_ENABLE();
break;
}
}
enable_clock_from_pin(int_pin);
enable_clock_from_pin(ce_pin);
enable_clock_from_pin(cs_pin);

I don't frown on that as I've done much more complicated ways to generalize device setups for on the fly configurations for OS systems software (with MMU and VM hardware protection) where applications programs need abstracted access to resources. It just that here, it's mainly candy that not really needed for single level zero access to resources.I should have known that, I've done that before but when you're hacking and tweaking it's easily done.
The proof-of-concept code was semi-hard-coded for SPI and GPIOA pins and so that was the root.
@nsaspook will frown on this but I added this little helper.
This works when using the helper macros I mentioned yesterday.C:private void enable_clock_from_pin(uint64_t pin) { // Enable the GPIO clock for the pin uint32_t base = (uint32_t)(DECODE_BASE(pin)); switch (base) { case GPIOA_BASE: __GPIOA_CLK_ENABLE(); break; case GPIOB_BASE: __GPIOB_CLK_ENABLE(); break; case GPIOC_BASE: __GPIOC_CLK_ENABLE(); break; case GPIOD_BASE: __GPIOD_CLK_ENABLE(); break; case GPIOE_BASE: __GPIOE_CLK_ENABLE(); break; case GPIOF_BASE: __GPIOF_CLK_ENABLE(); break; case GPIOG_BASE: __GPIOG_CLK_ENABLE(); break; case GPIOH_BASE: __GPIOH_CLK_ENABLE(); break; } }
e.g.
Code:enable_clock_from_pin(int_pin); enable_clock_from_pin(ce_pin); enable_clock_from_pin(cs_pin);
static void release_dma_chan(uint8_t chan)
{
assert(chan < DMA_NUMOF);
IEC4CLR = _IEC4_DMA0IE_MASK << chan; /* Disable the DMA interrupt. */
IFS4CLR = _IFS4_DMA0IF_MASK << chan; /* Clear the DMA interrupt flag. */
DCHxCON(pic_dma[chan]) = 0;
DCHxECON(pic_dma[chan]) = 0;
DCHxINT(pic_dma[chan]) = 0;
}
static void init_dma_chan(uint8_t chan, uint32_t irq_num, volatile unsigned int *SourceDma, volatile unsigned int *DestDma, spi_t bus)
{
assert(chan < DMA_NUMOF);
assert(bus != 0 && bus <= SPI_NUMOF_USED);
pic_dma[chan].regs = (volatile uint32_t *)(&DCH0CON + (chan * DMA_REGS_SPACING));
pic_dma[chan].bus = bus;
IEC4CLR = _IEC4_DMA0IE_MASK << chan; /* Disable the DMA chan interrupt. */
IFS4CLR = _IFS4_DMA0IF_MASK << chan; /* Clear the DMA chan interrupt flag. */
DMACONSET = _DMACON_ON_MASK; /* Enable the DMA module. */
DCHxCON(pic_dma[chan]) = 0;
DCHxECON(pic_dma[chan]) = 0;
DCHxINT(pic_dma[chan]) = 0;
DCHxSSA(pic_dma[chan]) = KVA_TO_PA(SourceDma); /* Source start address. */
DCHxDSA(pic_dma[chan]) = KVA_TO_PA(DestDma); /* Destination start address. */
DCHxSSIZ(pic_dma[chan]) = 1; /* default Source bytes. */
DCHxDSIZ(pic_dma[chan]) = 1; /* default Destination bytes. */
DCHxCSIZ(pic_dma[chan]) = 1; /* Bytes to transfer per event. */
DCHxECON(pic_dma[chan]) = irq_num << _DCH0ECON_CHSIRQ_POSITION; /* cell trigger interrupt */
DCHxECONSET(pic_dma[chan]) = _DCH0ECON_SIRQEN_MASK; /* Start cell transfer if an interrupt matching CHSIRQ occurs */
DCHxINTSET(pic_dma[chan]) = _DCH0INT_CHBCIE_MASK; /* enable Channel block transfer complete interrupt. */
/*
* set vector priority and receiver DMA trigger enables for the board hardware configuration
*/
*(dma_config[chan].ipc_regset) = dma_config[chan].ipc_mask_p & (SPIxPRI_SW0 << dma_config[chan].ipc_mask_pos_p);
*(dma_config[chan].ipc_regset) = dma_config[chan].ipc_mask_s & (SPIxSUBPRI_SW0 << dma_config[chan].ipc_mask_pos_s);
IEC4SET = dma_config[chan].iec_mask << chan; /* DMA interrupt enable if needed */
}
/* disable receive interrupts and set the UART buffer mode for DMA */
static void spi_reset_dma_irq(spi_t bus)
{
assert(bus != 0 && bus <= SPI_NUMOF_USED);
switch (bus) {
case 1:
IEC3CLR = _IEC3_SPI1RXIE_MASK; /* disable SPIxRX interrupt */
SPI1CONbits.SRXISEL = 1; /* not empty */
IFS3CLR = _IFS3_SPI1RXIF_MASK; /* clear SPIxRX flag */
break;
case 2:
IEC4CLR = _IEC4_SPI2RXIE_MASK;
SPI2CONbits.SRXISEL = 1;
IFS4CLR = _IFS4_SPI2RXIF_MASK;
break;
default:
break;
}
}
static void trigger_bus_dma_tx(uint8_t chan, size_t len, uint32_t physSourceDma)
{
assert(chan < DMA_NUMOF);
DCHxSSA(pic_dma[chan]) = physSourceDma;
DCHxSSIZ(pic_dma[chan]) = (len & _DCH0SSIZ_CHSSIZ_MASK);
DCHxCONSET(pic_dma[chan]) = _DCH0CON_CHEN_MASK; /* Channel enable. */
}
static void trigger_bus_dma_rx(uint8_t chan, size_t len, uint32_t physDestDma)
{
assert(chan < DMA_NUMOF);
spi_reset_dma_irq(pic_dma[chan].bus);
DCHxDSA(pic_dma[chan]) = physDestDma;
DCHxDSIZ(pic_dma[chan]) = (len & _DCH0DSIZ_CHDSIZ_MASK);
DCHxCONSET(pic_dma[chan]) = _DCH0CON_CHEN_MASK; /* Channel enable. */
}
/* adjust speed on the fly, these extra functions are prototyped in board.h */
void spi_speed_config(spi_t bus, spi_mode_t mode, spi_clk_t clk)
{
assert(bus != 0 && bus <= SPI_NUMOF_USED);
pic_spi[bus].regs = (volatile uint32_t *)(_SPI1_BASE_ADDRESS + (bus - 1) * SPI_REGS_SPACING);
SPIxCONCLR(pic_spi[bus]) = (_SPI1CON_ON_MASK);
if (clk) {
SPIxBRG(pic_spi[bus]) = (PERIPHERAL_CLOCK / (2 * clk)) - 1;
}
switch (mode) {
case SPI_MODE_0:
SPIxCONCLR(pic_spi[bus]) = _SPI1CON_CKP_MASK;
SPIxCONSET(pic_spi[bus]) = _SPI1CON_CKE_MASK;
break;
case SPI_MODE_1:
SPIxCONCLR(pic_spi[bus]) = (_SPI1CON_CKP_MASK | _SPI1CON_CKE_MASK);
break;
case SPI_MODE_2:
SPIxCONCLR(pic_spi[bus]) = _SPI1CON_CKE_MASK;
SPIxCONSET(pic_spi[bus]) = _SPI1CON_CKP_MASK;
break;
case SPI_MODE_3:
SPIxCONSET(pic_spi[bus]) = (_SPI1CON_CKP_MASK | _SPI1CON_CKE_MASK);
break;
default:
break;
}
SPIxCONSET(pic_spi[bus]) = (_SPI1CON_ON_MASK);
}
/* 1,2,3 are the active spi devices on the cpicmzef board configuration
* DMA channels are allocated for 1&2 tx/rx
*/
static void spi_irq_enable(spi_t bus)
{
uint32_t mask;
assert(bus != 0 && bus <= SPI_NUMOF_USED);
/* set enable and flag mask */
mask = spi_config[bus].int_mask;
*(spi_config[bus].iec_regclr) = mask; /* disable SPIxRX interrupt */
switch (bus) {
case 1:
init_dma_chan(SPI1_DMA_TX, _SPI1_TX_VECTOR, &SPI1BUF, &SPI1BUF, bus);
init_dma_chan(SPI1_DMA_RX, _SPI1_RX_VECTOR, &SPI1BUF, &SPI1BUF, bus);
break;
case 2:
init_dma_chan(SPI2_DMA_TX, _SPI2_TX_VECTOR, &SPI2BUF, &SPI2BUF, bus);
init_dma_chan(SPI2_DMA_RX, _SPI2_RX_VECTOR, &SPI2BUF, &SPI2BUF, bus);
break;
default:
break;
}
SPIxCONCLR(pic_spi[bus]) = _SPI1CON_SRXISEL_MASK & (3 << _SPI1CON_SRXISEL_POSITION); /* clear all */
/* interrupt when not full */
SPIxCONSET(pic_spi[bus]) = _SPI1CON_SRXISEL_MASK & (1 << _SPI1CON_SRXISEL_POSITION); /* set mode */
/* last transfer is shifted out */
SPIxCONCLR(pic_spi[bus]) = _SPI1CON_STXISEL_MASK & (3 << _SPI1CON_STXISEL_POSITION); /* clear all */
/*
* set vector priority and receiver interrupt enables for the board hardware configuration
*/
*(spi_config[bus].ifs_regclr) = mask; /* clear SPIxRX flag */
*(spi_config[bus].ipc_regset) = spi_config[bus].ipc_mask_p & (SPIxPRI_SW0 << spi_config[bus].ipc_mask_pos_p);
*(spi_config[bus].ipc_regset) = spi_config[bus].ipc_mask_s & (SPIxSUBPRI_SW0 << spi_config[bus].ipc_mask_pos_s);
*(spi_config[bus].iec_regset) = mask; /* enable SPIxRX interrupt */
}