Better integration of SPI with DMA and IRQ. Using only 'End' IRQ. Perf could be improved by using 'Started' IRQ to prepare the next buffer while the current one is beeing sent.

This commit is contained in:
JF
2020-01-26 13:37:10 +01:00
parent eb7a1b3ac9
commit 5fa4f5abe0
10 changed files with 223 additions and 164 deletions

View File

@@ -0,0 +1,11 @@
#pragma once
#include <cstddef>
namespace Pinetime {
namespace Drivers {
class BufferProvider {
public:
virtual bool GetNextBuffer(uint8_t** buffer, size_t& size) = 0;
};
}
}

View File

@@ -4,10 +4,9 @@
#include <algorithm>
using namespace Pinetime::Drivers;
SpiMaster* spiInstance;
SpiMaster::SpiMaster(const SpiMaster::SpiModule spi, const SpiMaster::Parameters &params) :
spi{spi}, params{params} {
spiInstance = this;
}
bool SpiMaster::Init() {
@@ -84,12 +83,33 @@ void SpiMaster::setup_workaround_for_ftpan_58(NRF_SPIM_Type *spim, uint32_t ppi_
NRF_PPI->CHENSET = 1U << ppi_channel;
}
void SpiMaster::irqStarted() {
if(busy) {
auto s = currentBufferSize;
if(s > 0) {
auto currentSize = std::min((size_t)255, s);
void SpiMaster::OnEndEvent(BufferProvider& provider) {
if(!busy) return;
auto s = currentBufferSize;
if(s > 0) {
auto currentSize = std::min((size_t) 255, s);
NRF_SPIM0->TXD.PTR = (uint32_t) currentBufferAddr;
NRF_SPIM0->TXD.MAXCNT = currentSize;
NRF_SPIM0->TXD.LIST = 0;
currentBufferAddr += currentSize;
currentBufferSize -= currentSize;
NRF_SPIM0->RXD.PTR = (uint32_t) 0;
NRF_SPIM0->RXD.MAXCNT = 0;
NRF_SPIM0->RXD.LIST = 0;
NRF_SPIM0->TASKS_START = 1;
} else {
uint8_t* buffer = nullptr;
size_t size = 0;
if(provider.GetNextBuffer(&buffer, size)) {
currentBufferAddr = (uint32_t) buffer;
currentBufferSize = size;
auto s = currentBufferSize;
auto currentSize = std::min((size_t)255, s);
NRF_SPIM0->TXD.PTR = (uint32_t) currentBufferAddr;
NRF_SPIM0->TXD.MAXCNT = currentSize;
NRF_SPIM0->TXD.LIST = 0;
@@ -101,44 +121,19 @@ void SpiMaster::irqStarted() {
NRF_SPIM0->RXD.MAXCNT = 0;
NRF_SPIM0->RXD.LIST = 0;
if(repeat == 0)
NRF_SPIM0->SHORTS = 0;
return;
}else {
if(repeat > 0) {
repeat = repeat -1;
currentBufferAddr = bufferAddr;
currentBufferSize = bufferSize;
s = currentBufferSize;
auto currentSize = std::min((size_t)255, s);
NRF_SPIM0->TXD.PTR = (uint32_t) currentBufferAddr;
NRF_SPIM0->TXD.MAXCNT = currentSize;
NRF_SPIM0->TXD.LIST = 0;
currentBufferAddr += currentSize;
currentBufferSize -= currentSize;
NRF_SPIM0->RXD.PTR = (uint32_t) 0;
NRF_SPIM0->RXD.MAXCNT = 0;
NRF_SPIM0->RXD.LIST = 0;
}
}
}
}
void SpiMaster::irqEnd() {
if(busy) {
if(repeat == 0 && currentBufferSize == 0) {
nrf_gpio_pin_set(pinCsn);
NRF_SPIM0->TASKS_START = 1;
} else {
busy = false;
nrf_gpio_pin_set(pinCsn);
}
}
}
void SpiMaster::OnStartedEvent(BufferProvider& provider) {
if(!busy) return;
}
bool SpiMaster::Write(const uint8_t *data, size_t size, size_t r) {
bool SpiMaster::Write(const uint8_t *data, size_t size) {
if(data == nullptr) return false;
while(busy) {
@@ -162,16 +157,12 @@ bool SpiMaster::Write(const uint8_t *data, size_t size, size_t r) {
nrf_gpio_pin_clear(pinCsn);
currentBufferAddr = bufferAddr = (uint32_t)data;
currentBufferSize = bufferSize = size;
repeat = r;
currentBufferAddr = (uint32_t)data;
currentBufferSize = size;
busy = true;
if(repeat > 0)
NRF_SPIM0->SHORTS = (1<<17);
auto currentSize = std::min((size_t)255, bufferSize);
NRF_SPIM0->TXD.PTR = bufferAddr;
auto currentSize = std::min((size_t)255, (size_t)currentBufferSize);
NRF_SPIM0->TXD.PTR = currentBufferAddr;
NRF_SPIM0->TXD.MAXCNT = currentSize;
NRF_SPIM0->TXD.LIST = 0;
@@ -187,21 +178,11 @@ bool SpiMaster::Write(const uint8_t *data, size_t size, size_t r) {
if(size == 1) {
while (NRF_SPIM0->EVENTS_END == 0);
busy = false;
nrf_gpio_pin_set(pinCsn);
}
return true;
}
bool SpiMaster::GetStatusEnd() {
return (bool)*(volatile uint32_t *)((uint8_t *)spiBaseAddress + (uint32_t)NRF_SPIM_EVENT_END);
}
bool SpiMaster::GetStatusStarted() {
return (bool)*(volatile uint32_t *)((uint8_t *)spiBaseAddress + (uint32_t)NRF_SPIM_EVENT_STARTED);
}
void SpiMaster::Sleep() {
while(NRF_SPIM0->ENABLE != 0) {
NRF_SPIM0->ENABLE = (SPIM_ENABLE_ENABLE_Disabled << SPIM_ENABLE_ENABLE_Pos);
@@ -216,8 +197,4 @@ void SpiMaster::Wakeup() {
Init();
}
void SpiMaster::Wait() {
while(busy) {
asm("nop");
}
}

View File

@@ -3,6 +3,8 @@
#include <cstddef>
#include <array>
#include <atomic>
#include "BufferProvider.h"
namespace Pinetime {
namespace Drivers {
class SpiMaster {
@@ -23,20 +25,17 @@ namespace Pinetime {
SpiMaster(const SpiModule spi, const Parameters& params);
bool Init();
bool Write(const uint8_t* data, size_t size, size_t r = 0);
void setup_workaround_for_ftpan_58(NRF_SPIM_Type *spim, uint32_t ppi_channel, uint32_t gpiote_channel);
void Wait();
bool Write(const uint8_t* data, size_t size);
void OnStartedEvent(BufferProvider& provider);
void OnEndEvent(BufferProvider& provider);
void Sleep();
void Wakeup();
bool GetStatusEnd();
bool GetStatusStarted();
void irqEnd();
void irqStarted();
private:
void setup_workaround_for_ftpan_58(NRF_SPIM_Type *spim, uint32_t ppi_channel, uint32_t gpiote_channel);
NRF_SPIM_Type * spiBaseAddress;
uint8_t pinCsn;
@@ -44,12 +43,8 @@ namespace Pinetime {
SpiMaster::Parameters params;
volatile bool busy = false;
uint32_t bufferAddr = 0;
volatile uint32_t currentBufferAddr = 0;
size_t bufferSize = 0;
volatile size_t currentBufferSize = 0;
volatile uint32_t repeat = 0;
};
}
}

View File

@@ -37,8 +37,8 @@ void St7789::WriteData(uint8_t data) {
}
void St7789::WriteSpi(const uint8_t* data, size_t size, size_t repeat) {
spi.Write(data, size, repeat);
void St7789::WriteSpi(const uint8_t* data, size_t size) {
spi.Write(data, size);
}
void St7789::SoftwareReset() {
@@ -142,12 +142,8 @@ void St7789::BeginDrawBuffer(uint16_t x, uint16_t y, uint16_t width, uint16_t he
nrf_gpio_pin_set(pinDataCommand);
}
void St7789::EndDrawBuffer() {
spi.Wait();
}
void St7789::NextDrawBuffer(const uint8_t *data, size_t size, size_t repeat) {
WriteSpi(data, size, repeat);
void St7789::NextDrawBuffer(const uint8_t *data, size_t size) {
WriteSpi(data, size);
}
void St7789::HardwareReset() {
@@ -178,5 +174,3 @@ void St7789::Wakeup() {
NormalModeOn();
DisplayOn();
}

View File

@@ -12,16 +12,13 @@ namespace Pinetime {
void DrawPixel(uint16_t x, uint16_t y, uint32_t color);
void BeginDrawBuffer(uint16_t x, uint16_t y, uint16_t width, uint16_t height);
void NextDrawBuffer(const uint8_t* data, size_t size, size_t repeat = 0);
void EndDrawBuffer();
void NextDrawBuffer(const uint8_t* data, size_t size);
void DisplayOn();
void DisplayOff();
void Sleep();
void Wakeup();
private:
SpiMaster& spi;
uint8_t pinDataCommand;
@@ -35,12 +32,9 @@ namespace Pinetime {
void DisplayInversionOn();
void NormalModeOn();
void WriteToRam();
void SetAddrWindow(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1);
void WriteCommand(uint8_t cmd);
void WriteSpi(const uint8_t* data, size_t size, size_t repeat = 0);
void WriteSpi(const uint8_t* data, size_t size);
enum class Commands : uint8_t {
SoftwareReset = 0x01,
@@ -62,7 +56,6 @@ namespace Pinetime {
static constexpr uint16_t Width = 240;
static constexpr uint16_t Height = 240;
void RowAddressSet();
};
}
}