Skip to content

Reworked SPI class with direct register access to fix #28 for R_SPI #45

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 17 commits into from
Jul 24, 2023
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
8499f96
- first draft for a much fast SPI class
RudolphRiedel Jul 8, 2023
1261299
Merge branch 'main' of https://github.com/RudolphRiedel/ArduinoCore-r…
RudolphRiedel Jul 8, 2023
6d7c1c2
- buffer transfers are even faster now by switching to 32 bit transfers
RudolphRiedel Jul 9, 2023
c6299c3
- added transfer(void *buf, void *rxbuf, size_t count), contributed b…
RudolphRiedel Jul 10, 2023
cf597fc
- more cleanup and testing
RudolphRiedel Jul 10, 2023
8c6c694
- minor coding guideline fixes
RudolphRiedel Jul 10, 2023
2d0bedc
- sped up transfer(buf, rxbuf, count) a little by making it use direc…
RudolphRiedel Jul 11, 2023
aa013bd
- more minor coding standard fixes
RudolphRiedel Jul 11, 2023
7df2144
- fix, a line from the SCI code in transfer(data) was missing
RudolphRiedel Jul 11, 2023
33d8348
- changes as requested for the pull-request
RudolphRiedel Jul 12, 2023
32446a5
- removed transfer(buf, rxbuf, t count) to comply with the requiremen…
RudolphRiedel Jul 12, 2023
0cc34e0
- moved the null-pointer check in transfer(buf, count) to start of th…
RudolphRiedel Jul 12, 2023
65072f1
There's no longer a need to register the SPI callback, since we are n…
aentinger Jul 13, 2023
23b9a00
- as requested in the pull-request, changed the test for nullpointer …
RudolphRiedel Jul 13, 2023
200f7e8
Merge branch 'main' of https://github.com/RudolphRiedel/ArduinoCore-r…
RudolphRiedel Jul 13, 2023
0d5733f
Also remove forward declaration of FSP callback "spi_callback" which …
aentinger Jul 13, 2023
1cb3111
- fix: SPCR2.SCKASE needs to be set to protect the SPI from delays in…
RudolphRiedel Jul 13, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
296 changes: 233 additions & 63 deletions libraries/SPI/SPI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -164,22 +164,8 @@ void ArduinoSPI::begin()
init_ok = false;
}
}
else
{
SpiMasterIrqReq_t irq_req
{
.ctrl = &_spi_ctrl,
.cfg = &_spi_cfg,
.hw_channel = (uint8_t)_channel,
};
init_ok &= IRQManager::getInstance().addPeripheral(IRQ_SPI_MASTER, &irq_req);

if (FSP_SUCCESS == _open(&_spi_ctrl, &_spi_cfg)) {
init_ok &= true;
} else {
init_ok = false;
}
}
/* not using FSP for SPI anymore and no interrupts */

_is_initialized = init_ok;
}
Expand All @@ -196,24 +182,31 @@ void ArduinoSPI::end()

uint8_t ArduinoSPI::transfer(uint8_t data)
{
uint8_t rxbuf;
_spi_cb_event[_cb_event_idx] = SPI_EVENT_TRANSFER_ABORTED;
if (_is_sci) {
_write_then_read(&_spi_sci_ctrl, &data, &rxbuf, 1, SPI_BIT_WIDTH_8_BITS);
} else {
_write_then_read(&_spi_ctrl, &data, &rxbuf, 1, SPI_BIT_WIDTH_8_BITS);
}
uint8_t rxbuf;

if (_is_sci) {
_spi_cb_event[_cb_event_idx] = SPI_EVENT_TRANSFER_ABORTED;

_write_then_read(&_spi_sci_ctrl, &data, &rxbuf, 1, SPI_BIT_WIDTH_8_BITS);

for (auto const start = millis();
(SPI_EVENT_TRANSFER_COMPLETE != _spi_cb_event[_cb_event_idx]) && (millis() - start < 1000); )
{
__NOP();
}
if (SPI_EVENT_TRANSFER_ABORTED == _spi_cb_event[_cb_event_idx])
{
end();
return 0;
}
}
else
{
_spi_ctrl.p_regs->SPDR_BY = data;
while (0U == _spi_ctrl.p_regs->SPSR_b.SPRF) {}
rxbuf = _spi_ctrl.p_regs->SPDR_BY;
}

for (auto const start = millis();
(SPI_EVENT_TRANSFER_COMPLETE != _spi_cb_event[_cb_event_idx]) && (millis() - start < 1000); )
{
__NOP();
}
if (SPI_EVENT_TRANSFER_ABORTED == _spi_cb_event[_cb_event_idx])
{
end();
return 0;
}
return rxbuf;
}

Expand All @@ -234,23 +227,158 @@ uint16_t ArduinoSPI::transfer16(uint16_t data)

void ArduinoSPI::transfer(void *buf, size_t count)
{
_spi_cb_event[_cb_event_idx] = SPI_EVENT_TRANSFER_ABORTED;
if (_is_sci) {
_spi_cb_event[_cb_event_idx] = SPI_EVENT_TRANSFER_ABORTED;

if (_is_sci) {
_write_then_read(&_spi_sci_ctrl, buf, buf, count, SPI_BIT_WIDTH_8_BITS);
} else {
_write_then_read(&_spi_ctrl, buf, buf, count, SPI_BIT_WIDTH_8_BITS);
}
_write_then_read(&_spi_sci_ctrl, buf, buf, count, SPI_BIT_WIDTH_8_BITS);

for (auto const start = millis();
(SPI_EVENT_TRANSFER_COMPLETE != _spi_cb_event[_cb_event_idx]) && (millis() - start < 1000); )
{
__NOP();
}
if (SPI_EVENT_TRANSFER_ABORTED == _spi_cb_event[_cb_event_idx])
{
end();
}
for (auto const start = millis();
(SPI_EVENT_TRANSFER_COMPLETE != _spi_cb_event[_cb_event_idx]) && (millis() - start < 1000); )
{
__NOP();
}
if (SPI_EVENT_TRANSFER_ABORTED == _spi_cb_event[_cb_event_idx])
{
end();
}
}
else
{
if (buf != NULL) {
uint32_t *buffer32 = (uint32_t *) buf;
size_t index_rx = 0;
size_t index_tx = 0;
size_t const n32 = count / 4U;
uint8_t const bytes_remaining = (uint8_t) (count & 3U);

if (n32 != 0U) {
_spi_ctrl.p_regs->SPCR_b.SPE = 0; /* disable SPI unit */
_spi_ctrl.p_regs->SPDCR = R_SPI0_SPDCR_SPLW_Msk; /* SPI word access */
_spi_ctrl.p_regs->SPCMD_b[0].SPB = 2; /* spi bit width = 32 */
_spi_ctrl.p_regs->SPCR_b.SPE = 1; /* enable SPI unit */

while ((index_tx < 2U) && (index_tx < n32)) {
if (_spi_ctrl.p_regs->SPSR_b.SPTEF) {
_spi_ctrl.p_regs->SPDR = buffer32[index_tx];
index_tx++;
}
}

while (index_tx < n32) {
if (_spi_ctrl.p_regs->SPSR_b.SPRF) {
uint32_t tmp = _spi_ctrl.p_regs->SPDR;
_spi_ctrl.p_regs->SPDR = buffer32[index_tx];
buffer32[index_rx] = tmp;
index_rx++;
index_tx++;
}
}

while (index_rx < n32) { /* collect the last word received */
if (_spi_ctrl.p_regs->SPSR_b.SPRF) {
uint32_t tmp = _spi_ctrl.p_regs->SPDR;
buffer32[index_rx] = tmp;
index_rx++;
}
}

_spi_ctrl.p_regs->SPCR_b.SPE = 0; /* disable SPI unit */
_spi_ctrl.p_regs->SPDCR = R_SPI0_SPDCR_SPBYT_Msk; /* SPI byte access */
_spi_ctrl.p_regs->SPCMD_b[0].SPB = 7; /* spi bit width = 8 */
_spi_ctrl.p_regs->SPCR_b.SPE = 1; /* enable SPI unit */
}

/* send the remaining bytes with 8-bit transfers */
uint8_t *buffer = (uint8_t *) &buffer32[index_rx];

for (uint8_t index = 0; index < bytes_remaining; index++) {
_spi_ctrl.p_regs->SPDR_BY = buffer[index];
while (0U == _spi_ctrl.p_regs->SPSR_b.SPRF) {}
buffer[index] = _spi_ctrl.p_regs->SPDR_BY;
}
}
}
}

void ArduinoSPI::transfer(void *buf, void *rxbuf, size_t count)
{
if (_is_sci) {
_spi_cb_event[_cb_event_idx] = SPI_EVENT_TRANSFER_ABORTED;

_write_then_read(&_spi_sci_ctrl, buf, rxbuf, count, SPI_BIT_WIDTH_8_BITS);

for (auto const start = millis();
(SPI_EVENT_TRANSFER_COMPLETE != _spi_cb_event[_cb_event_idx]) && (millis() - start < 1000); )
{
__NOP();
}
if (SPI_EVENT_TRANSFER_ABORTED == _spi_cb_event[_cb_event_idx])
{
end();
}
}
else {
size_t n32 = count / 4U;
if (n32 != 0U) {
_spi_ctrl.p_regs->SPCR_b.SPE = 0; /* disable SPI unit */
_spi_ctrl.p_regs->SPDCR = R_SPI0_SPDCR_SPLW_Msk; /* SPI word access */
_spi_ctrl.p_regs->SPCMD_b[0].SPB = 2; /* spi bit width = 32 */
_spi_ctrl.p_regs->SPCR_b.SPE = 1; /* enable SPI unit */

const uint32_t* tx32 = (const uint32_t *) buf;
uint32_t* rx32 = (uint32_t *) rxbuf;
size_t index_rx = 0;
size_t index_tx = 0;

while ((index_tx < 2U) && (index_tx < n32)) {
if (_spi_ctrl.p_regs->SPSR_b.SPTEF) {
_spi_ctrl.p_regs->SPDR = (buf != NULL) ? tx32[index_tx] : 0xFFFFFFFF;
index_tx++;
}
}

while (index_tx < n32) {
if (_spi_ctrl.p_regs->SPSR_b.SPRF) {
uint32_t tmp = _spi_ctrl.p_regs->SPDR;
_spi_ctrl.p_regs->SPDR = (buf != NULL) ? tx32[index_tx] : 0xFFFFFFFF;
if (rxbuf != NULL) {
rx32[index_rx] = tmp;
}
index_rx++;
index_tx++;
}
}

while (index_rx < n32) { /* collect the last word received */
if (_spi_ctrl.p_regs->SPSR_b.SPRF) {
uint32_t tmp = _spi_ctrl.p_regs->SPDR;
if (rxbuf != NULL) {
rx32[index_rx] = tmp;
}
index_rx++;
}
}

_spi_ctrl.p_regs->SPCR_b.SPE = 0; /* disable SPI unit */
_spi_ctrl.p_regs->SPDCR = R_SPI0_SPDCR_SPBYT_Msk; /* SPI byte access */
_spi_ctrl.p_regs->SPCMD_b[0].SPB = 7; /* spi bit width = 8 */
_spi_ctrl.p_regs->SPCR_b.SPE = 1; /* enable SPI unit */
}

/* send the remaining bytes with 8-bit transfers */
if (count != (4U * n32)) {
uint8_t *rx = (uint8_t *) rxbuf;
const uint8_t* tx = (const uint8_t *) buf;
for (size_t i = 4U * n32; i < count; i++) {
_spi_ctrl.p_regs->SPDR_BY = (buf != NULL) ? tx[i] : 0xFF;
while (0U == _spi_ctrl.p_regs->SPSR_b.SPRF) {}
uint8_t tmp = _spi_ctrl.p_regs->SPDR_BY;
if (rxbuf != NULL) {
rx[i] = tmp;
}
}
}
}
}

void ArduinoSPI::beginTransaction(arduino::SPISettings settings)
Expand Down Expand Up @@ -366,29 +494,71 @@ void ArduinoSPI::configSpiSettings(arduino::SPISettings const & settings)

void ArduinoSPI::configSpi(arduino::SPISettings const & settings)
{
auto [clk_phase, clk_polarity, bit_order] = toFspSpiConfig(settings);
/** SPI base register access macro. */
#define SPI_REG(channel) ((R_SPI0_Type *) ((uint32_t) R_SPI0 + \
((uint32_t) R_SPI1 - (uint32_t) R_SPI0) * (channel)))

rspck_div_setting_t spck_div = _spi_ext_cfg.spck_div;
R_SPI_CalculateBitrate(settings.getClockFreq(), &spck_div);
_spi_ctrl.p_cfg = &_spi_cfg;
_spi_ctrl.p_callback = _spi_cfg.p_callback;
_spi_ctrl.p_context = _spi_cfg.p_context;
_spi_ctrl.p_callback_memory = NULL;
_spi_ctrl.p_regs = SPI_REG(_spi_ctrl.p_cfg->channel);

uint32_t spcmd0 = _spi_ctrl.p_regs->SPCMD[0];
auto [clk_phase, clk_polarity, bit_order] = toFspSpiConfig(settings);
rspck_div_setting_t spck_div = _spi_ext_cfg.spck_div;
R_SPI_CalculateBitrate(settings.getClockFreq(), &spck_div);

/* Configure CPHA setting. */
spcmd0 |= (uint32_t) clk_phase;
_spi_ctrl.p_regs->SPCR = 0; /* disable SPI unit */

/* Configure CPOL setting. */
spcmd0 |= (uint32_t) clk_polarity << 1;
/* Power up the SPI module. */
R_BSP_MODULE_START(FSP_IP_SPI, _spi_cfg.channel);

/* Configure Bit Order (MSB,LSB) */
spcmd0 |= (uint32_t) bit_order << 12;
/* configure SSLn polarity setting. */
uint32_t sslp = 0;
sslp |= (uint32_t) _spi_ext_cfg.ssl_polarity << _spi_ext_cfg.ssl_select;
_spi_ctrl.p_regs->SSLP = (uint8_t) sslp;

/* Configure the Bit Rate Division Setting */
spcmd0 &= ~(((uint32_t) 3) << 2);
spcmd0 |= (uint32_t) spck_div.brdv << 2;
uint32_t sppcr = 0;
/* set MOSI idle value to low */
sppcr |= R_SPI0_SPPCR_MOIFE_Msk;
_spi_ctrl.p_regs->SPPCR = (uint8_t) sppcr;

/* Update settings. */
_spi_ctrl.p_regs->SPCMD[0] = (uint16_t) spcmd0;
_spi_ctrl.p_regs->SPBR = (uint8_t) spck_div.spbr;
/* configure bit rate */
_spi_ctrl.p_regs->SPBR = (uint8_t) spck_div.spbr;

/* the SPBYT bit in SPDCR is documented only by "Technical Update" */
_spi_ctrl.p_regs->SPDCR_b.SPBYT = 1; /* SPI byte access */

/* register undocumented for the RA4M1 but found to be working and necessary */
/* BYSW - Byte Swap Operating Mode Select - 1 = Byte Swap ON - essential for 32 bit transfers */
_spi_ctrl.p_regs->SPDCR2_b.BYSW = 1;

_spi_ctrl.p_regs->SPCKD = 0;

_spi_ctrl.p_regs->SSLND = 0;

_spi_ctrl.p_regs->SPND = 0;

_spi_ctrl.p_regs->SPCR2 = 0;

/* SPMS = 0 -> SPI operation, TXMD = 0 -> full-duplex, SPxIE = 0 -> no interrupts */
if (SPI_MODE_MASTER == _spi_cfg.operating_mode) {
_spi_ctrl.p_regs->SPCR_b.MSTR = 1;
}

_spi_ctrl.p_regs->SPCMD[0] = 0;
_spi_ctrl.p_regs->SPCMD_b[0].CPHA = clk_phase;
_spi_ctrl.p_regs->SPCMD_b[0].CPOL = clk_polarity;
_spi_ctrl.p_regs->SPCMD_b[0].BRDV = spck_div.brdv; /* set bit rate division */
_spi_ctrl.p_regs->SPCMD_b[0].SPB = 7; /* spi bit width = 8 */
_spi_ctrl.p_regs->SPCMD_b[0].LSBF = bit_order;

_spi_ctrl.p_regs->SPSR; /* read to clear OVRF */
_spi_ctrl.p_regs->SPSR = 0; /* clear status register */

_spi_ctrl.p_regs->SPCR_b.SPE = 1; /* enable SPI unit */

_spi_ctrl.open = (0x52535049ULL); /* "SPI" in ASCII, used to determine if channel is open. */
}

void ArduinoSPI::configSpiSci(arduino::SPISettings const & settings)
Expand Down
1 change: 1 addition & 0 deletions libraries/SPI/SPI.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ class ArduinoSPI : public SPIClass
virtual uint8_t transfer(uint8_t data);
virtual uint16_t transfer16(uint16_t data);
virtual void transfer(void *buf, size_t count);
virtual void transfer(void *buf, void *rxbuf, size_t count);

// Transaction Functions
virtual void usingInterrupt(int __attribute__((unused)) interruptNumber) { }
Expand Down