Hi everyone,
I’m currently working on an SPI driver for the BeagleBone Black (AM335x). The existing driver uses libi2c, but I’m developing it with the spi_bus framework.
Right now, my plan is to support:
- Runtime parameter updates (speed, mode, bits per word, etc.)
- Polling transfers
- Interrupt-driven transfers
- DMA transfers
- Support for both SPI controllers available on the AM335x
My goal is to make it a general-purpose driver that fits well with the existing RTEMS SPI framework, rather than something that only works for my current use case.
Before I go too far with the implementation, I’d like to make sure I’m heading in the right direction. Are there any requirements, design considerations, or common pitfalls that I should keep in mind so the driver aligns with RTEMS expectations and is suitable for upstream contribution?
Thanks for letting us know. Looks good and the support would be most welcome. Keep us updated here.
Im just beginner in driver development of any kind. So what i want to know is that using old function like setting pins and using am335x.h which has memory address macros will be ok?. And Am335x.h doesn’t have some definition which i want to use so can i update it?
And im trying to work on transfer function which uses old libi2c transfer with IRQ with even parameter passing.
And transfer supports 64 buffer at a time bcz 64 FIFO limit.
I want to transfer continously using IRQ mode.
But this won’t happen with old style.
I don’t know how to do this.
Polling method is easy so it works but i havent add any RTOS parameters to it.
typedef struct {
spi_bus base;
uintptr_t regs;
uint8_t *rx_buf;
const uint8_t *tx_buf;
// bool turbo;
// bool fifo;
// bool pin_mode;
uint8_t transfer_mode;
uint8_t channel_num;
uint8_t clock_mode;
uint32_t ctrl_mode;
// uint32_t inclk;
rtems_id task_id;
rtems_vector_number irq;
bool initialized;
} am335x_spi_bus;
this my current struct which i have defined.
And i m using the official function of TI to set clock parameters.
static void am335x_clk_config(am335x_spi_bus *bus)
{
unsigned int fRatio = 0;
unsigned int extClk = 0;
unsigned int clkD = 0;
unsigned int reg_base = bus->regs;
unsigned int chNum = bus->channel_num;
unsigned int spiInClk = bus->base.max_speed_hz;
unsigned int spiOutClk = bus->base.speed_hz;
unsigned int clkMode = bus->clock_mode;
fRatio = (spiInClk / spiOutClk);
if(0 != (fRatio & (fRatio - 1)))
{
REG(reg_base + AM335X_SPI_CHCONF(chNum)) |= AM335X_SPI_CH0CONF_CLKG ;
extClk = (fRatio - 1) >> 4;
clkD = (fRatio - 1) & MCSPI_CLKD_MASK;
REG(reg_base + AM335X_SPI_CHCTRL(chNum)) &= AM335X_SPI_CH0CTRL_EXTCLK;
REG(reg_base + AM335X_SPI_CHCTRL(chNum)) |= (extClk <<
AM335X_SPI_CH0CTRL_EXTCLK_SHIFT);
}
else
{
REG(reg_base + AM335X_SPI_CHCONF(chNum)) &= ~AM335X_SPI_CH0CONF_CLKG;
while(1 != fRatio)
{
fRatio /= 2;
clkD++;
}
}
REG( reg_base + AM335X_SPI_CH0CONF) |= AM335X_SPI_CH0CONF_DPE0;
REG( reg_base + AM335X_SPI_CH0CONF) &= ~AM335X_SPI_CH0CONF_DPE1;
REG( reg_base + AM335X_SPI_CH0CONF) &= ~AM335X_SPI_CH0CONF_IS;
REG(reg_base + AM335X_SPI_CHCONF(chNum)) &= ~AM335X_SPI_CH0CONF_CLKDM;
REG(reg_base + AM335X_SPI_CHCONF(chNum)) |= (clkD <<AM335X_SPI_CH0CONF_CLKD_SHIFT);
REG(reg_base + AM335X_SPI_CHCONF(chNum)) &= ~(AM335X_SPI_CH0CONF_PHA |
AM335X_SPI_CH0CONF_POL);
REG(reg_base +AM335X_SPI_CHCONF(chNum)) |= (clkMode & (AM335X_SPI_CH0CONF_PHA |
AM335X_SPI_CH0CONF_POL));
REG(reg_base + AM335X_SPI_CH0CONF) |= AM335X_SPI_CH0CONF_EPOL;
printf("SPI clock configured: input clock %u Hz, output clock %u Hz, clkD %u, extClk %u, clkMode 0x%02X\n", spiInClk, spiOutClk, clkD, extClk, clkMode);
}
Moving to the cpukit/dev/spi driver would be great.
Yes update am335x.h to add what you use.
I have not looked at this hardware in detail. Can you control when the interrupt fires? They sometime fire before the data has been sent so you have time to queue another frame of data.
So i’m thinking like this.
Generate interrupt for first TX_EMPTY event and then continously transfer
bytes with checking condition on register with disabled interrupt.
Then enable and interrupt with transfer complete event.
I want to know what will be professional design for transfer with interrupt.