Open Model Railroad Network (OpenMRN)
Loading...
Searching...
No Matches
CC32xxSPI.hxx
Go to the documentation of this file.
1
34#ifndef _FREERTOS_DRIVERS_TI_CC32XXSPI_HXX_
35#define _FREERTOS_DRIVERS_TI_CC32XXSPI_HXX_
36
37#ifndef gcc
38#define gcc
39#endif
40
41#include <cstdint>
42
43#include "SPI.hxx"
44
45#include "inc/hw_mcspi.h"
46#include "inc/hw_types.h"
47#include "driverlib/udma.h"
48
49#include <ti/drivers/dma/UDMACC32XX.h>
50
53class CC32xxSPI : public SPI, private Atomic
54{
55public:
71 CC32xxSPI(const char *name, unsigned long base, uint32_t interrupt,
72 ChipSelectMethod cs_assert, ChipSelectMethod cs_deassert,
73 OSMutex *bus_lock = nullptr,
74 size_t dma_threshold = DEFAULT_DMA_THRESHOLD_BYTES,
75 uint32_t dma_channel_index_tx = UDMA_CH7_GSPI_TX,
76 uint32_t dma_channel_index_rx = UDMA_CH6_GSPI_RX);
77
81 {
82 }
83
87 void interrupt_handler();
88
96 {
97 return &lock_;
98 }
99
100private:
101 static constexpr size_t DEFAULT_DMA_THRESHOLD_BYTES = 64;
102
104 static constexpr size_t MAX_DMA_TRANSFER_AMOUNT = 1024;
105
111 static constexpr uint32_t dmaRxConfig_[] =
112 {
113 UDMA_SIZE_8 | UDMA_SRC_INC_NONE | UDMA_DST_INC_8 | UDMA_ARB_1,
114 UDMA_SIZE_16 | UDMA_SRC_INC_NONE | UDMA_DST_INC_16 | UDMA_ARB_1,
115 UDMA_SIZE_32 | UDMA_SRC_INC_NONE | UDMA_DST_INC_32 | UDMA_ARB_1
116 };
117
123 static constexpr uint32_t dmaTxConfig_[] =
124 {
125 UDMA_SIZE_8 | UDMA_SRC_INC_8 | UDMA_DST_INC_NONE | UDMA_ARB_1,
126 UDMA_SIZE_16 | UDMA_SRC_INC_16 | UDMA_DST_INC_NONE | UDMA_ARB_1,
127 UDMA_SIZE_32 | UDMA_SRC_INC_32 | UDMA_DST_INC_NONE | UDMA_ARB_1
128 };
129
135 static constexpr uint32_t dmaNullConfig_[] =
136 {
137 UDMA_SIZE_8 | UDMA_SRC_INC_NONE | UDMA_DST_INC_NONE | UDMA_ARB_1,
138 UDMA_SIZE_16 | UDMA_SRC_INC_NONE | UDMA_DST_INC_NONE | UDMA_ARB_1,
139 UDMA_SIZE_32 | UDMA_SRC_INC_NONE | UDMA_DST_INC_NONE | UDMA_ARB_1
140 };
141
144 void enable() override
145 {
146 dmaHandle_ = UDMACC32XX_open();
147 }
148
151 void disable() override
152 {
153 UDMACC32XX_close(dmaHandle_);
154 }
155
159 int update_configuration() override;
160
164 __attribute__((optimize("-O3")))
165 int transfer(struct spi_ioc_transfer *msg) override
166 {
167 if (LIKELY(msg->len < dmaThreshold_))
168 {
169 return transfer_polled(msg);
170 }
171 else
172 {
173 /* use DMA */
174 config_dma(msg);
175 }
176
177 return msg->len;
178 }
179
184 template<typename T>
185 __attribute__((optimize("-O3")))
186 int transfer_polled(struct spi_ioc_transfer *msg)
187 {
188 T dummy = 0;
189
190 /* we are assuming that at least one byte will be transferred, and
191 * we want to start tranfering data as soon as possible
192 */
193 data_put(msg->tx_buf ? *((T*)msg->tx_buf) : 0xFFFFFFFF);
194
195 T *tx_buf = msg->tx_buf ? ((T*)msg->tx_buf) + 1 : &dummy;
196 T *rx_buf = (T*)msg->rx_buf;
197
198 /* note that we already have transmitted one SPI word above, hence the
199 * subtract one from the tx_len
200 */
201 uint32_t rx_len = msg->len / sizeof(T);
202 uint32_t tx_len = rx_len - 1;
203
204 unsigned long data;
205
206 do
207 {
208 /* fill TX FIFO but make sure we don't fill it to overflow */
209 if (tx_len && ((rx_len - tx_len) < (32 / sizeof(T))))
210 {
211 if (data_put_non_blocking(*tx_buf) != 0)
212 {
213 if (msg->tx_buf)
214 {
215 ++tx_buf;
216 }
217 --tx_len;
218 }
219 }
220
221 /* empty RX FIFO */
222 if (rx_len)
223 {
224 if (data_get_non_blocking(&data) != 0)
225 {
226 if (msg->rx_buf)
227 {
228 *rx_buf++ = data;
229 }
230 --rx_len;
231 }
232 }
233 }
234 while (tx_len || rx_len);
235
236 return msg->len;
237 }
238
242 __attribute__((optimize("-O3")))
243 int transfer_polled(struct spi_ioc_transfer *msg) override
244 {
245 /* set instance specific configuration */
247
248 switch (bitsPerWord)
249 {
250 default:
251 case 8:
252 return transfer_polled<uint8_t>(msg);
253 case 16:
254 return transfer_polled<uint16_t>(msg);
255 case 32:
256 return transfer_polled<uint32_t>(msg);
257 }
258 }
259
263 void config_dma(struct spi_ioc_transfer *msg);
264
270 __attribute__((optimize("-O3")))
271 long data_get_non_blocking(unsigned long *data)
272 {
273 if(HWREG(base_ + MCSPI_O_CH0STAT) & MCSPI_CH0STAT_RXS)
274 {
275 *data = HWREG(base_ + MCSPI_O_RX0);
276 return 1;
277 }
278
279 return 0;
280 }
281
287 __attribute__((optimize("-O3")))
288 long data_put_non_blocking(unsigned long data)
289 {
290 if(HWREG(base_ + MCSPI_O_CH0STAT) & MCSPI_CH0STAT_TXS)
291 {
292 HWREG(base_ + MCSPI_O_TX0) = data;
293 return 1;
294 }
295
296 return 0;
297 }
298
304 void data_put(unsigned long data)
305 {
306 while(UNLIKELY(!(HWREG(base_ + MCSPI_O_CH0STAT)&MCSPI_CH0STAT_TXS)));
307
308 HWREG(base_ + MCSPI_O_TX0) = data;
309 }
310
314 {
315 HWREG(base_ + MCSPI_O_CH0CTRL) = spiChctrl_;
316 HWREG(base_ + MCSPI_O_CH0CONF) = spiChconf_;
317 HWREG(base_ + MCSPI_O_XFERLEVEL) = spiXferlevel_;
318 }
319
320 UDMACC32XX_Handle dmaHandle_;
322 unsigned long base_;
323 unsigned long clock_;
324 unsigned long interrupt_;
328 uint32_t spiChctrl_;
329 uint32_t spiChconf_;
330 uint32_t spiXferlevel_;
335
337};
338
339#endif /* _FREERTOS_DRIVERS_TI_CC32XXSPI_HXX_ */
Lightweight locking class for protecting small critical sections.
Definition Atomic.hxx:130
Specialization of Serial SPI driver for CC32xx devices.
Definition CC32xxSPI.hxx:54
int transfer(struct spi_ioc_transfer *msg) override
Method to transmit/receive the data.
long data_get_non_blocking(unsigned long *data)
Receives a word from the specified port.
static constexpr uint32_t dmaRxConfig_[]
This lookup table is used to configure the DMA channels for the appropriate (8bit,...
int transfer_polled(struct spi_ioc_transfer *msg)
Method to transmit/receive the data.
static constexpr uint32_t dmaTxConfig_[]
This lookup table is used to configure the DMA channels for the appropriate (8bit,...
static constexpr uint32_t dmaNullConfig_[]
This lookup table is used to configure the DMA channels for the appropriate (8bit,...
unsigned long clock_
clock rate supplied to the module
uint32_t dmaChannelIndexRx_
RX DMA channel index.
CC32xxSPI()
Default constructor.
void data_put(unsigned long data)
Waits until the word is transmitted on the specified port.
void set_configuration()
Set the instance local configuration.
long data_put_non_blocking(unsigned long data)
Transmits a word on the specified port.
void disable() override
Function to disable device.
~CC32xxSPI()
Destructor.
Definition CC32xxSPI.hxx:80
size_t dmaThreshold_
threshold in bytes to start using DMA
uint32_t spiChctrl_
instance local copy of configuration
static constexpr size_t MAX_DMA_TRANSFER_AMOUNT
Maximum number of bytes transferred in a single DMA transaction.
uint32_t dmaChannelIndexTx_
TX DMA channel index.
OSMutex * get_lock()
This method provides a reference to the Mutex used by this device driver.
Definition CC32xxSPI.hxx:95
UDMACC32XX_Handle dmaHandle_
handle to DMA reference
void interrupt_handler()
handle an interrupt.
OSSem * sem_
reference to the semaphore belonging to this bus
uint32_t spiXferlevel_
instance local copy of configuration
uint32_t spiChconf_
instance local copy of configuration
unsigned long interrupt_
interrupt of this device
void config_dma(struct spi_ioc_transfer *msg)
Configure a DMA transaction.
int update_configuration() override
Update the configuration of the bus.
void enable() override
Function to enable device.
unsigned long base_
base address of this device
const char * name
device name
Definition Devtab.hxx:266
OSMutex lock_
protects internal structures.
Definition Devtab.hxx:588
This class provides a mutex API.
Definition OS.hxx:427
This class provides a counting semaphore API.
Definition OS.hxx:243
Private data for an SPI device.
Definition SPI.hxx:53
void bus_lock()
Lock the bus shared by many chip selects.
Definition SPI.hxx:141
uint8_t bitsPerWord
number of bits per word transaction
Definition SPI.hxx:193
void(* ChipSelectMethod)()
Function point for the chip select assert and deassert methods.
Definition SPI.hxx:56
#define DISALLOW_COPY_AND_ASSIGN(TypeName)
Removes default copy-constructor and assignment added by C++.
Definition macros.h:171