117 lines
3.5 KiB
C++
117 lines
3.5 KiB
C++
|
#include "system.h"
|
||
|
#include "spiclass.h"
|
||
|
typedef __SIZE_TYPE__ size_t;
|
||
|
|
||
|
enum SPICLK : uint32_t {
|
||
|
FPCLK_2 = 0u, // 72 MHz
|
||
|
FPCLK_4, // 36 MHz
|
||
|
FPCLK_8, // 18 MHz
|
||
|
FPCLK_16, // 9 MHz
|
||
|
FPCLK_32, // 4.5 MHz
|
||
|
FPCLK_64, // 2.25 MHz
|
||
|
FPCLK_128, // 1.125 MHz
|
||
|
FPCLK_256, // 0.5625 MHz
|
||
|
};
|
||
|
|
||
|
static SpiClass * pSpiInstance = nullptr;
|
||
|
extern "C" {
|
||
|
//[[gnu::interrupt]] extern void DMA1_Channel2_IRQHandler();
|
||
|
[[gnu::interrupt]] extern void DMA1_Channel3_IRQHandler();
|
||
|
extern void * memcpy (void * dest, const void * src, size_t n);
|
||
|
};
|
||
|
void DMA1_Channel3_IRQHandler() { // transmit channel
|
||
|
if (pSpiInstance) pSpiInstance->drq();
|
||
|
}
|
||
|
static constexpr unsigned FM = 3u; // 50 MHz
|
||
|
static void InitPins () noexcept {
|
||
|
// PA4 - NSS, PA5 - SCK, PA6 - MISO, PA7 - MOSI
|
||
|
GPIOA.CFGLR.modify([](GPIOA_Type::CFGLR_DEF & r) -> uint32_t {
|
||
|
/*r.B.MODE4 = FM;
|
||
|
r.B.CNF4 = 2u; // alt push - pull
|
||
|
r.B.MODE6 = 0u; // input mode
|
||
|
r.B.CNF6 = 1u; // floating */
|
||
|
r.B.MODE5 = FM;
|
||
|
r.B.CNF5 = 2u; // alt push - pull
|
||
|
r.B.MODE7 = FM;
|
||
|
r.B.CNF7 = 2u; // alt push - pull
|
||
|
return r.R;
|
||
|
});
|
||
|
// AFIO - default
|
||
|
}
|
||
|
void SpiClass::drq() {
|
||
|
if (!driver) return;
|
||
|
DMA1_Type::INTFR_DEF state (DMA1.INTFR);
|
||
|
if (state.B.HTIF3) {
|
||
|
DMA1.INTFCR.B.CHTIF3 = SET; // clear half
|
||
|
driver->Send (ptrl, HALF_LEN, true);
|
||
|
}
|
||
|
if (state.B.TCIF3) {
|
||
|
DMA1.INTFCR.B.CTCIF3 = SET; // clear complete
|
||
|
//driver->Send (ptrh, HALF_LEN, false); // reset
|
||
|
}
|
||
|
}
|
||
|
|
||
|
SpiClass::SpiClass(OneWay<uint8_t> & base) noexcept : driver (& base), ptrl (buffer), ptrh (buffer + HALF_LEN) {
|
||
|
pSpiInstance = this;
|
||
|
for (unsigned n=0u; n<FULL_LEN; n++) buffer[n] = 0u;
|
||
|
Color * ptr = reinterpret_cast<Color*>(ptrl);
|
||
|
const OneColor oz(0x00);
|
||
|
for (unsigned n=0; n<NUMLEDS; n++) {
|
||
|
Color & c = ptr [n];
|
||
|
c.b = oz; c.g = oz; c.r = oz;
|
||
|
}
|
||
|
}
|
||
|
void SpiClass::Init() {
|
||
|
RCC.APB2PCENR.modify([](RCC_Type::APB2PCENR_DEF & r) -> uint32_t {
|
||
|
r.B.SPI1EN = SET;
|
||
|
r.B.IOPAEN = SET;
|
||
|
r.B.AFIOEN = SET;
|
||
|
return r.R;
|
||
|
});
|
||
|
RCC.AHBPCENR.B.DMA1EN = SET;
|
||
|
InitPins();
|
||
|
// Configure the peripheral data register address
|
||
|
DMA1.PADDR3.R = reinterpret_cast<size_t> (& SPI1.DATAR);
|
||
|
// Configure the memory address
|
||
|
DMA1.MADDR3.R = reinterpret_cast<size_t> (buffer);
|
||
|
// Configure the number of DMA tranfer to be performs on DMA channel 3
|
||
|
DMA1.CNTR3 .R = FULL_LEN;
|
||
|
// Configure increment, size, interrupts and circular mode
|
||
|
DMA1.CFGR3.modify([] (DMA1_Type::CFGR3_DEF & r) -> uint32_t {
|
||
|
r.B.PL = 3u; // highest priority
|
||
|
r.B.DIR = SET; // memory -> periferal
|
||
|
r.B.MINC = SET; // memory increment
|
||
|
r.B.MSIZE = 0u; // 8-bit
|
||
|
r.B.PSIZE = 0u; // 8-bit
|
||
|
r.B.HTIE = SET; // INT Enable HALF
|
||
|
r.B.TCIE = SET; // INT Enable FULL
|
||
|
r.B.CIRC = SET; // Circular MODE
|
||
|
// Enable DMA Channel 1
|
||
|
r.B.EN = SET;
|
||
|
return r.R;
|
||
|
});
|
||
|
SPI1.CTLR1.modify([](SPI1_Type::CTLR1_DEF & r) -> uint32_t {
|
||
|
r.B.CPHA = RESET;
|
||
|
r.B.CPOL = RESET;
|
||
|
r.B.MSTR = SET;
|
||
|
r.B.DFF = RESET; // 8 bit
|
||
|
r.B.SSM = SET;
|
||
|
r.B.SSI = SET;
|
||
|
r.B.LSBFIRST = SET;
|
||
|
/* 2.25 MHz - 1bit = 444 ns
|
||
|
* 1 LED 9 x 8 x 0.444 = 32 us DMA celkem 16 x 32 = 0.512 ms
|
||
|
* */
|
||
|
r.B.BR = FPCLK_64;
|
||
|
return r.R;
|
||
|
});
|
||
|
SPI1.CTLR2.modify([](SPI1_Type::CTLR2_DEF & r) -> uint32_t {
|
||
|
r.B.SSOE = SET;
|
||
|
//r.B.RXNEIE = SET;
|
||
|
//r.B.TXEIE = SET;
|
||
|
r.B.TXDMAEN = SET;
|
||
|
return r.R;
|
||
|
});
|
||
|
NVIC.EnableIRQ(DMA1_Channel3_IRQn);
|
||
|
SPI1.CTLR1.B.SPE = SET;
|
||
|
}
|