Kinda works

This commit is contained in:
Attila Body 2021-10-31 00:33:00 +02:00
parent f3d345e2e3
commit 662a7a9b12
40 changed files with 2851 additions and 26 deletions

View file

@ -0,0 +1,194 @@
/*
* interrupt.c
*
* Created on: Aug 29, 2019
* Author: abody
*/
#include <f4ll_cpp/crcscheduler.h>
#include <string.h>
#if defined(HAVE_DIAG)
#include "diag.h"
#endif
#include "f4ll_cpp/dmahelper.h"
#ifndef DIAG_CRC_CALC_START
# define DIAG_CRC_CALC_START()
#endif
#ifndef DIAG_CRC_CALC_END
# define DIAG_CRC_CALC_END()
#endif
#ifndef DIAG_INTERRUPT_IN
# define DIAG_INTERRUPT_IN()
#endif
#ifndef DIAG_INTERRUPT_OUT
# define DIAG_INTERRUPT_OUT()
#endif
namespace f4ll_cpp
{
void Crc_StartNextTask(struct crcstatus_t *status);
CrcScheduler::CrcScheduler(CRC_TypeDef *crcUnit, DMA_TypeDef *dma, uint32_t stream) :
m_dma(dma, stream),
m_activeSlot(nullptr),
m_firstSlot(nullptr)
{
m_crcUnit = crcUnit;
LL_DMA_EnableIT_TC(dma, stream);
LL_DMA_EnableIT_TE(dma, stream);
LL_DMA_SetM2MDstAddress(dma, stream, (uint32_t)&crcUnit->DR);
}
void CrcScheduler::AttachTasks(struct crcslot_t *slot, struct crctask_t *tasks, uint8_t taskCount)
{
slot->count = taskCount;
slot->tasks = tasks;
memset(tasks, 0, sizeof(*tasks)*taskCount);
uint32_t prim = __get_PRIMASK();
__disable_irq();
slot->next = m_firstSlot;
m_firstSlot = slot;
__set_PRIMASK(prim);
}
uint8_t CrcScheduler::GetActiveTask(struct crcslot_t **slot_out)
{
uint8_t ret;
uint32_t prim = __get_PRIMASK();
__disable_irq();
ret = m_activeTask;
if(slot_out)
*slot_out = (struct crcslot_t *) m_activeSlot;
__set_PRIMASK(prim);
return ret;
}
bool CrcScheduler::IsTaskQueued(struct crcslot_t *slot, uint8_t task) {
return ((struct crctask_t volatile)slot->tasks[task]).address != NULL;
}
bool CrcScheduler::IsTaskBusy(struct crcslot_t *slot, uint8_t task) {
struct crctask_t volatile *taskPtr = &slot->tasks[task];
return taskPtr->callback != NULL || taskPtr->callbackParam != NULL;
}
void CrcScheduler::WaitResults(struct crcslot_t *slot, uint8_t task) {
while(IsTaskBusy(slot, task));
}
uint8_t CrcScheduler::Enqueue(struct crcslot_t *slot, uint8_t task, void *address, uint16_t len,
ICrcCallback* callback, void* callbackParam)
{
uint32_t prim = __get_PRIMASK();
bool need_start;
//struct crcstatus_t volatile *st = status;
while(IsTaskBusy(slot, task));
__disable_irq();
need_start = (m_activeSlot == nullptr);
slot->tasks[task].address = need_start ? NULL : address;
slot->tasks[task].wordCount = (len+3)/4;
slot->tasks[task].callback = callback;
slot->tasks[task].callbackParam = callbackParam;
if(need_start) {
m_activeSlot = slot;
m_activeTask = task;
}
__set_PRIMASK(prim);
if(need_start) {
DIAG_CRC_CALC_START();
m_crcUnit->CR = 1;
LL_DMA_SetM2MSrcAddress(m_dma.GetDma(), m_dma.GetStream(), (uint32_t)address);
LL_DMA_SetDataLength(m_dma.GetDma(), m_dma.GetStream(), (len+3)/4);
DIAG_CRC_CALC_START();
LL_DMA_EnableStream(m_dma.GetDma(), m_dma.GetStream());
}
return need_start;
}
uint32_t CrcScheduler::Compute(struct crcslot_t *slot, uint8_t task, void *address, uint16_t len)
{
uint32_t result;
Enqueue(slot, task, address, len, NULL, &result);
while((struct crcslot_t volatile *)slot->tasks[task].callbackParam);
return result;
}
// only called from ISR context
void CrcScheduler::StartNextTask()
{
char moreTasks;
uint8_t index = 0;
do {
struct crcslot_t *slot = m_firstSlot;
moreTasks = 0;
while(slot) {
if(index < slot->count) {
if(slot->tasks[index].address) {
DIAG_CRC_CALC_START();
m_activeSlot = slot;
m_activeTask = index;
m_crcUnit->CR = 1;
LL_DMA_SetM2MSrcAddress(m_dma.GetDma(), m_dma.GetStream(), (uint32_t)slot->tasks[index].address);
LL_DMA_SetDataLength(m_dma.GetDma(), m_dma.GetStream(), slot->tasks[index].wordCount);
LL_DMA_EnableStream(m_dma.GetDma(), m_dma.GetStream());
slot->tasks[index].address = nullptr; // marking as started
return;
}
if(index + 1 < slot->count)
moreTasks = 1;
}
slot = slot->next;
}
++index;
} while(moreTasks);
m_activeSlot = nullptr;
}
// !!!PORTABILITY WARNING!!! using registers and bits directly. should be reviewed extremely when porting to a different MCU
void CrcScheduler::_HandleDmaIrq()
{
uint8_t success = 1;
DIAG_INTERRUPT_IN();
if((*m_dma.GetIsReg() & m_dma.GetTcMask()) ||
(*m_dma.GetIsReg() & m_dma.GetTeMask())) {
if(*m_dma.GetIsReg() & m_dma.GetTeMask())
success = 0;
*m_dma.GetIfcReg() = *m_dma.GetIsReg() & (m_dma.GetTcMask() | m_dma.GetTeMask());
LL_DMA_DisableStream(m_dma.GetDma(), m_dma.GetStream());
if(m_activeSlot) {
crctask_t *tsk = &m_activeSlot->tasks[m_activeTask];
if(tsk->callback)
tsk->callback->CrcCalculationCompleted(tsk->callbackParam, m_crcUnit->DR, success);
else if(tsk->callbackParam)
*(uint32_t*)tsk->callbackParam = success ? m_crcUnit->DR : 0xffffffff;
tsk->callback = nullptr;
tsk->callbackParam = nullptr; // marking as inactive
DIAG_CRC_CALC_END();
StartNextTask();
}
}
DIAG_INTERRUPT_OUT();
}
} // f4ll_cpp

View file

@ -0,0 +1,72 @@
/*
* interrupt.h
*
* Created on: Aug 29, 2019
* Author: abody
*/
#ifndef CRC_HANDLER_H_
#define CRC_HANDLER_H_
#include <inttypes.h>
#ifdef HAVE_CONFIG
#include "config.h"
#endif // HAVE_CONFIG
#include <platform/crc_ll.h>
#include <f4ll_cpp/dmahelper.h>
namespace f4ll_cpp
{
class CrcScheduler {
public:
struct ICrcCallback {
virtual void CrcCalculationCompleted(void*, uint32_t, uint8_t) = 0;
};
struct crctask_t {
void * volatile address;
uint16_t wordCount;
ICrcCallback* callback;
void *callbackParam;
};
struct crcslot_t {
uint16_t count;
struct crcslot_t *next;
struct crctask_t *tasks;
};
CrcScheduler(CRC_TypeDef *crcUnit, DMA_TypeDef *dma, uint32_t stream);
uint8_t GetActiveTask(struct crcslot_t **slot_out);
bool IsTaskQueued(struct crcslot_t *slot, uint8_t task);
bool IsTaskBusy(struct crcslot_t *slot, uint8_t task);
void WaitResults(struct crcslot_t *slot, uint8_t task);
void AttachTasks(struct crcslot_t *slot, struct crctask_t *tasks, uint8_t taskCount);
uint8_t Enqueue(struct crcslot_t *slot, uint8_t task, void *address, uint16_t len,
ICrcCallback* callback, void* callbackParam);
uint32_t Compute(struct crcslot_t *slot, uint8_t task, void *address, uint16_t len);
static void HandleDmaIrq(void *param) { reinterpret_cast<CrcScheduler*>(param)->_HandleDmaIrq(); }
void _HandleDmaIrq();
private:
void StartNextTask();
CRC_TypeDef *m_crcUnit;
DmaHelper m_dma;
volatile crcslot_t *m_activeSlot;
volatile uint8_t m_activeTask;
crcslot_t *m_firstSlot;
};
} // f4ll_cpp
#endif /* CRC_HANDLER_H_ */

View file

@ -0,0 +1,86 @@
/*
* dma_helper.c
*
* Created on: Sep 18, 2019
* Author: abody
*/
#include <f4ll_cpp/dmahelper.h>
#ifndef MOCKABLE
#define MOCKABLE(x) x
#endif
namespace f4ll_cpp
{
DmaHelper::DmaHelper(DMA_TypeDef *dma, uint32_t stream)
{
m_dma = dma;
m_stream = stream;
m_isReg = _GetIsReg(dma, stream);
m_ifcReg = _GetIfcReg(dma, stream);
m_feMask = _GetFeMask(stream);
m_dmeMask = _GetDmeMask(stream);
m_teMask = _GetTeMask(stream);
m_htMask = _GetHtMask(stream);
m_tcMask = _GetTcMask(stream);
}
volatile uint32_t* DmaHelper::_GetIsReg(DMA_TypeDef *dma, uint32_t stream)
{
if(dma == DMA1)
return (stream < LL_DMA_STREAM_4) ? &DMA1->LISR : &DMA1->HISR;
else
return (stream < LL_DMA_STREAM_4) ? &DMA2->LISR : &DMA2->HISR;
}
volatile uint32_t* DmaHelper::_GetIfcReg(DMA_TypeDef *dma, uint32_t stream)
{
if(dma == DMA1)
return (stream < LL_DMA_STREAM_4) ? &DMA1->LIFCR : &DMA1->HIFCR;
else
return (stream < LL_DMA_STREAM_4) ? &DMA2->LIFCR : &DMA2->HIFCR;
}
uint32_t DmaHelper::_GetFeMask(uint32_t stream)
{
static const uint32_t feMasks[8] = {
DMA_LISR_FEIF0, DMA_LISR_FEIF1, DMA_LISR_FEIF2, DMA_LISR_FEIF3, DMA_HISR_FEIF4, DMA_HISR_FEIF5, DMA_HISR_FEIF6, DMA_HISR_FEIF7
};
return feMasks[stream];
}
uint32_t DmaHelper::_GetDmeMask(uint32_t stream)
{
static const uint32_t dmeMasks[8] = {
DMA_LISR_DMEIF0, DMA_LISR_DMEIF1, DMA_LISR_DMEIF2, DMA_LISR_DMEIF3, DMA_HISR_DMEIF4, DMA_HISR_DMEIF5, DMA_HISR_DMEIF6, DMA_HISR_DMEIF7
};
return dmeMasks[stream];
}
uint32_t DmaHelper::_GetTeMask(uint32_t stream)
{
static const uint32_t teMasks[8] = {
DMA_LISR_TEIF0, DMA_LISR_TEIF1, DMA_LISR_TEIF2, DMA_LISR_TEIF3, DMA_HISR_TEIF4, DMA_HISR_TEIF5, DMA_HISR_TEIF6, DMA_HISR_TEIF7
};
return teMasks[stream];
}
uint32_t DmaHelper::_GetHtMask(uint32_t stream)
{
static const uint32_t htMasks[8] = {
DMA_LISR_HTIF0, DMA_LISR_HTIF1, DMA_LISR_HTIF2, DMA_LISR_HTIF3, DMA_HISR_HTIF4, DMA_HISR_HTIF5, DMA_HISR_HTIF6, DMA_HISR_HTIF7
};
return htMasks[stream];
}
uint32_t DmaHelper::_GetTcMask(uint32_t stream)
{
static const uint32_t tcMasks[8] = {
DMA_LISR_TCIF0, DMA_LISR_TCIF1, DMA_LISR_TCIF2, DMA_LISR_TCIF3, DMA_HISR_TCIF4, DMA_HISR_TCIF5, DMA_HISR_TCIF6, DMA_HISR_TCIF7
};
return tcMasks[stream];
}
} // f4ll_cpp

View file

@ -0,0 +1,57 @@
/*
* dma_helper.h
*
* Created on: Sep 18, 2019
* Author: abody
*/
#ifndef DMA_HELPER_H_
#define DMA_HELPER_H_
#include <inttypes.h>
#include <platform/dma_ll.h>
#ifndef DECLARE_MOCK
#define DECLARE_MOCK(x)
#endif
namespace f4ll_cpp
{
class DmaHelper {
public:
DmaHelper(DMA_TypeDef *dma, uint32_t stream);
DMA_TypeDef* GetDma() { return m_dma; }
uint32_t GetStream() { return m_stream; }
volatile uint32_t* GetIsReg() { return m_isReg; }
volatile uint32_t* GetIfcReg() { return m_ifcReg; }
uint32_t GetDmeMask() { return m_dmeMask; }
uint32_t GetTeMask() { return m_teMask; }
uint32_t GetHtMask() { return m_htMask; }
uint32_t GetTcMask() { return m_tcMask; }
uint32_t GetFeMask() { return m_feMask; }
private:
static volatile uint32_t* _GetIsReg(DMA_TypeDef *dma, uint32_t stream);
static volatile uint32_t* _GetIfcReg(DMA_TypeDef *dma, uint32_t stream);
static uint32_t _GetDmeMask(uint32_t stream);
static uint32_t _GetTeMask(uint32_t stream);
static uint32_t _GetHtMask(uint32_t stream);
static uint32_t _GetTcMask(uint32_t stream);
static uint32_t _GetFeMask(uint32_t stream);
private:
DMA_TypeDef *m_dma;
uint32_t m_stream;
volatile uint32_t *m_isReg;
volatile uint32_t *m_ifcReg;
uint32_t m_feMask;
uint32_t m_dmeMask;
uint32_t m_teMask;
uint32_t m_htMask;
uint32_t m_tcMask;
};
} // f4ll_cpp
#endif /* DMA_HELPER_H_ */

View file

@ -0,0 +1,404 @@
#include <f4ll_cpp/ili9341.h>
#include <platform/core_ll.h>
#include <inttypes.h>
#include <string.h>
#include <stdarg.h>
#include <FreeRTOS.h>
#include <task.h>
#define LCD_L 320
#define LCD_S 240
#define LCD_W LCD_L
#define LCD_H LCD_S
#define LCD_REG (*((volatile unsigned short *) 0x60000000)) /* DC = 0 */
#define LCD_RAM (*((volatile unsigned short *) 0x60080000)) /* DC = 1 */
#define RGB2U16(R,G,B) ((R & 0xf8) << 8 | (G & 0xfc) << 3 | (B & 0xf8) >> 3)
#define MSBSPLIT(x) ((uint8_t)(x >> 8)), ((uint8_t)x)
namespace f4ll_cpp {
Ili9341Fsmc::Ili9341Fsmc(volatile uint16_t *reg, volatile uint16_t *ram,
DMA_TypeDef *dma, uint32_t dmaStream,
bool horizontal)
: DmaHelper(dma, dmaStream)
, m_reg(reg ? reg : (volatile unsigned short *) 0x60000000)
, m_ram(ram ? ram : (volatile unsigned short *) 0x60080000)
, m_width(horizontal ? LCD_L : LCD_S)
, m_height(horizontal ? LCD_S : LCD_L)
, m_rectX(0)
, m_rectY(0)
, m_rectWidth(m_width)
, m_rectHeight(m_height)
{
LL_DMA_EnableIT_TC(GetDma(), GetStream());
LL_DMA_EnableIT_TE(GetDma(), GetStream());
WriteCmd(ILI9341_RESET);
vTaskDelay(pdMS_TO_TICKS(10));
WriteCmd(ILI9341_DISPLAY_OFF);
WriteCmd(ILI9341_POWERA, {0x39, 0x2C, 0x00, 0x34, 0x02});
WriteCmd(ILI9341_POWERB, {0x00, 0xC1, 0x30});
WriteCmd(ILI9341_DTCA, {0x85, 0x00, 0x78});
WriteCmd(ILI9341_DTCB, {0x00, 0x00});
WriteCmd(ILI9341_POWER_SEQ, {0x64, 0x03, 0x12, 0x81});
WriteCmd(ILI9341_PRC, 0x20);
WriteCmd(ILI9341_POWER1, 0x23);
WriteCmd(ILI9341_POWER2, 0x10);
WriteCmd(ILI9341_VCOM1, {0x3E, 0x28});
WriteCmd(ILI9341_VCOM2, 0x86);
WriteCmd(ILI9341_MAC, horizontal ? 0xe8 : 0x48);
WriteCmd(ILI9341_PIXEL_FORMAT, 0x55);
WriteCmd(ILI9341_FRC, {0x00, 0x18});
WriteCmd(ILI9341_DFC, {0x08, 0x82, 0x27});
WriteCmd(ILI9341_3GAMMA_EN, 0x00);
WriteCmd(ILI9341_COLUMN_ADDR, {0x00, 0x00, (uint16_t)((m_width-1) >> 8), (uint16_t)((m_width-1) & 0x00ff)});
WriteCmd(ILI9341_PAGE_ADDR, {0x00, 0x00, (uint16_t)((m_height-1) >> 8), (uint16_t)((m_height-1) & 0x00ff)});
WriteCmd(ILI9341_GAMMA, 0x01);
WriteCmd(ILI9341_PGAMMA, {0x0F, 0x31, 0x2B, 0x0C, 0x0E, 0x08, 0x4E, 0xF1, 0x37, 0x07, 0x10, 0x03, 0x0E, 0x09, 0x00});
WriteCmd(ILI9341_NGAMMA, {0x00, 0x0E, 0x14, 0x03, 0x11, 0x07, 0x31, 0xC1, 0x48, 0x08, 0x0F, 0x0C, 0x31, 0x36, 0x0F});
WriteCmd(ILI9341_SLEEP_OUT);
vTaskDelay(pdMS_TO_TICKS(100));
WriteCmd(ILI9341_DISPLAY_ON);
}
void Ili9341Fsmc::WriteCmd(uint16_t cmd, std::initializer_list<const uint16_t> params)
{
*m_reg = cmd;
for(uint16_t param : params)
*m_ram = param;
}
void Ili9341Fsmc::WriteCmd_(uint16_t cmd, uint16_t cnt, ...)
{
va_list argp;
va_start(argp, cnt);
*m_reg = cmd;
for(uint16_t n = 0; n < cnt; ++n) {
*m_ram = (uint16_t) va_arg(argp, uint32_t);
}
va_end(argp);
}
void Ili9341Fsmc::SetScrollMode(bool on)
{
if(on != m_scrollMode) {
if(on)
WriteCmd(ILI9341_VERTICAL_SCROLLING_DEFINITION, {0x00, 0x00, MSBSPLIT(m_height), 0x00, 0x00});
else
WriteCmd(ILI9341_NORMAL_DISPLAY_MODE_ON);
m_scrollMode = on;
}
}
void Ili9341Fsmc::WritePixels(void *src, uint32_t count, bool increment, bool async)
{
WriteCmd(ILI9341_GRAM);
LL_DMA_SetM2MDstAddress(GetDma(), GetStream(), (uint32_t)m_ram);
LL_DMA_SetMemoryIncMode(GetDma(), GetStream(), LL_DMA_MEMORY_NOINCREMENT);
LL_DMA_SetM2MSrcAddress(GetDma(), GetStream(), (uint32_t) src);
LL_DMA_SetPeriphIncMode(GetDma(), GetStream(), increment ? LL_DMA_PERIPH_NOINCREMENT : LL_DMA_PERIPH_NOINCREMENT);
SetupDmaSize(count);
m_dmaEngineBusy = true;
LL_DMA_EnableStream(GetDma(), GetStream());
if(!async)
WaitDmaIdle();
}
void Ili9341Fsmc::ReadGRam(PixelPair *dst, uint32_t count, bool async)
{
WriteCmd(ILI9341_MEMORY_READ);
*m_ram;
LL_DMA_SetM2MSrcAddress(GetDma(), GetStream(), reinterpret_cast<uint32_t>(m_ram));
LL_DMA_SetPeriphIncMode(GetDma(), GetStream(), LL_DMA_PERIPH_NOINCREMENT);
LL_DMA_SetM2MDstAddress(GetDma(), GetStream(), reinterpret_cast<uint32_t>(dst));
LL_DMA_SetMemoryIncMode(GetDma(), GetStream(), LL_DMA_MEMORY_INCREMENT);
SetupDmaSize(count);
m_dmaEngineBusy = true;
LL_DMA_EnableStream(GetDma(), GetStream());
if(!async)
WaitDmaIdle();
}
void Ili9341Fsmc::ReadPixels(uint16_t *dst, uint32_t count)
{
uint16_t *barrier = dst + count;
union {
PixelPair pp;
uint16_t u16[3];
} rawData;
WriteCmd(ILI9341_MEMORY_READ);
*m_ram;
do {
for(uint8_t n = 0; n < 3; ++n)
rawData.u16[n] = *m_ram;
*dst++ = RGB2U16(rawData.pp.r0, rawData.pp.g0, rawData.pp.b0);
if(dst != barrier)
*dst++ = RGB2U16(rawData.pp.r1, rawData.pp.g1, rawData.pp.b1);
} while(dst != barrier);
}
void Ili9341Fsmc::SetScrollOffset()
{
uint16_t offsetData[2] = { MSBSPLIT(m_scrollOffset) };
WriteCmd(ILI9341_VERTICAL_SCROLLING_START_ADDRESS);
*m_ram = offsetData[0];
*m_ram = offsetData[1];
}
void Ili9341Fsmc::SetRect(uint16_t x, uint16_t y, uint16_t width, uint16_t height)
{
if(x > m_width || y > m_height || !width || !height )
return;
WaitDmaIdle();
m_rectX = x;
m_rectY = y;
m_rectWidth = x + width > m_width ? m_width - x : width;
m_rectHeight = y + height > m_height ? m_height - x : height;
uint16_t right = x + m_rectWidth - 1;
uint16_t bottom = y + m_rectHeight - 1;
WriteCmd(ILI9341_COLUMN_ADDR, { MSBSPLIT(x), MSBSPLIT(right) });
WriteCmd(ILI9341_PAGE_ADDR, { MSBSPLIT(y), MSBSPLIT(bottom) });
}
void Ili9341Fsmc::FillRect(uint16_t color, bool async)
{
uint32_t count = m_rectWidth * m_rectHeight;
WaitDmaIdle();
m_dmaColor = color;
WritePixels(&m_dmaColor, count, false, async);
}
void Ili9341Fsmc::FillRect(uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint16_t color, bool async)
{
SetRect(x, y, width, height);
FillRect(color, async);
}
void Ili9341Fsmc::SetupDmaSize(uint32_t size)
{
if(size > 0xffff) {
LL_DMA_SetDataLength(GetDma(), GetStream(), 0xffff);
m_dmaRemainingPixels = size - 0xffff;
} else {
LL_DMA_SetDataLength(GetDma(), GetStream(), size);
m_dmaRemainingPixels = 0;
}
}
void Ili9341Fsmc::HandleDmaIrq()
{
if(*GetIsReg() & GetTcMask()) { //LL_DMA_IsActiveFlag_TCx(DMAy))
*GetIfcReg() = GetTcMask(); //LL_DMA_ClearFlag_TCx(DMAy)
LL_DMA_DisableStream(GetDma(), GetStream());
if(!m_dmaRemainingPixels)
m_dmaEngineBusy = false;
else {
SetupDmaSize(m_dmaRemainingPixels);
LL_DMA_EnableStream(GetDma(), GetStream());
}
} else if(*GetIsReg() & GetTeMask()) //LL_DMA_IsActiveFlag_TEx(DMAy))
*GetIfcReg() = GetTeMask(); // //LL_DMA_ClearFlag_TEx(DMAy)
}
void Ili9341Fsmc::SetCursor(uint16_t x, uint16_t y, uint16_t fgColor, uint16_t bgColor)
{
m_xPos = x;
m_yPos = y;
m_fgColor = fgColor;
m_bgColor = bgColor;
}
void Ili9341Fsmc::SetCursor(uint16_t x, uint16_t y)
{
m_xPos = x;
m_yPos = y;
}
void Ili9341Fsmc::PrintChar(char c, bool transparent)
{
// fonts are rotated, one byte representing one column
if(m_xPos > m_width - CHRWIDTH || m_yPos > m_height - CHRHEIGHT || c < ' ' || c >= '~')
return;
uint8_t const *chrPtr = m_font[c - 32];
SetRect(m_xPos, AdjustY(m_yPos), CHRWIDTH, CHRHEIGHT);
WaitDmaIdle();
if(transparent)
ReadPixels(m_fontBkgBuffer[0], CHRHEIGHT * CHRWIDTH);
WriteCmd(ILI9341_GRAM);
for(uint8_t y = 0; y < CHRHEIGHT; ++y ) {
uint8_t mask = 1 << y;
for(uint8_t x = 0; x < CHRWIDTH; ++x) {
*m_ram = (chrPtr[x] & mask) ? m_fgColor : (transparent ? m_fontBkgBuffer[y][x] : m_bgColor);
}
}
m_xPos += CHRWIDTH;
}
void Ili9341Fsmc::PrintChar(char c, uint16_t x, uint16_t y, uint16_t fgColor, uint16_t bgColor)
{
SetCursor(x, y, fgColor, bgColor);
PrintChar(c);
}
void Ili9341Fsmc::Print(char const *str, uint8_t len, bool transparent)
{
if(!len)
len = strlen(str);
while(len--) {
if(*str == '\r')
m_xPos = 0;
else if(*str == '\n') {
m_yPos += CHRHEIGHT;
if(m_yPos >= m_height) {
m_yPos -= CHRHEIGHT;
m_scrollOffset += CHRHEIGHT;
if(m_scrollOffset >= m_height)
m_scrollOffset -= m_height;
WaitDmaIdle();
SetScrollOffset();
if(!transparent)
FillRect(0, AdjustY(m_yPos), m_width, CHRHEIGHT, m_bgColor);
}
}
else
PrintChar(*str, transparent);
++str;
}
}
void Ili9341Fsmc::Test()
{
// static PixelPair linebuf[320/2];
// uint16_t x;
// WriteCmd(ILI9341_READ_DISPLAY_PIXEL_FORMAT);
// for( x= 0; x < 2; ++x)
// reinterpret_cast<uint16_t*>(linebuf)[x] = *m_ram;
// WriteCmd(ILI9341_GRAM);
// uint16_t fillers[4] = { 0xf800, 0x7e0, 0x1f, 0xffff };
// for(uint32_t y = 0; y < m_height; ++y) {
// for(x = 0; x < m_width / 2; ++x)
// *m_ram = fillers[ (x&0x18) >> 3 ];
// for( ; x < m_width; ++x)
// *m_ram = 0;
// }
//
// SetRect(0, 0, 11, 2);
// ReadGRam(linebuf, 11 * 3);
}
const uint8_t Ili9341Fsmc::m_font[CHRCOUNT][CHRWIDTH] = {
{0x00,0x00,0x00,0x00,0x00,0x00}, //
{0x2f,0x00,0x00,0x00,0x00,0x00}, // !
{0x03,0x00,0x03,0x00,0x00,0x00}, // "
{0x12,0x3f,0x12,0x12,0x3f,0x12}, // #
{0x2e,0x2a,0x7f,0x2a,0x3a,0x00}, // $
{0x23,0x13,0x08,0x04,0x32,0x31}, // %
{0x10,0x2a,0x25,0x2a,0x10,0x20}, // &
{0x02,0x01,0x00,0x00,0x00,0x00}, // '
{0x1e,0x21,0x00,0x00,0x00,0x00}, // (
{0x21,0x1e,0x00,0x00,0x00,0x00}, // )
{0x08,0x2a,0x1c,0x2a,0x08,0x08}, // *
{0x08,0x08,0x3e,0x08,0x08,0x08}, // +
{0x80,0x60,0x00,0x00,0x00,0x00}, // ,
{0x08,0x08,0x08,0x08,0x08,0x00}, // -
{0x30,0x30,0x00,0x00,0x00,0x00}, // .
{0x20,0x10,0x08,0x04,0x02,0x00}, // /
{0x1e,0x31,0x29,0x25,0x23,0x1e}, // 0
{0x22,0x21,0x3f,0x20,0x20,0x20}, // 1
{0x32,0x29,0x29,0x29,0x29,0x26}, // 2
{0x12,0x21,0x21,0x25,0x25,0x1a}, // 3
{0x18,0x14,0x12,0x3f,0x10,0x10}, // 4
{0x17,0x25,0x25,0x25,0x25,0x19}, // 5
{0x1e,0x25,0x25,0x25,0x25,0x18}, // 6
{0x01,0x01,0x31,0x09,0x05,0x03}, // 7
{0x1a,0x25,0x25,0x25,0x25,0x1a}, // 8
{0x06,0x29,0x29,0x29,0x29,0x1e}, // 9
{0x24,0x00,0x00,0x00,0x00,0x00}, // :
{0x80,0x64,0x00,0x00,0x00,0x00}, // ;
{0x08,0x14,0x22,0x00,0x00,0x00}, // <
{0x14,0x14,0x14,0x14,0x14,0x00}, // =
{0x22,0x14,0x08,0x00,0x00,0x00}, // >
{0x02,0x01,0x01,0x29,0x05,0x02}, // ?
{0x1e,0x21,0x2d,0x2b,0x2d,0x0e}, // @
{0x3e,0x09,0x09,0x09,0x09,0x3e}, // A
{0x3f,0x25,0x25,0x25,0x25,0x1a}, // B
{0x1e,0x21,0x21,0x21,0x21,0x12}, // C
{0x3f,0x21,0x21,0x21,0x12,0x0c}, // D
{0x3f,0x25,0x25,0x25,0x25,0x21}, // E
{0x3f,0x05,0x05,0x05,0x05,0x01}, // F
{0x1e,0x21,0x21,0x21,0x29,0x1a}, // G
{0x3f,0x04,0x04,0x04,0x04,0x3f}, // H
{0x21,0x21,0x3f,0x21,0x21,0x21}, // I
{0x10,0x20,0x20,0x20,0x20,0x1f}, // J
{0x3f,0x04,0x0c,0x0a,0x11,0x20}, // K
{0x3f,0x20,0x20,0x20,0x20,0x20}, // L
{0x3f,0x02,0x04,0x04,0x02,0x3f}, // M
{0x3f,0x02,0x04,0x08,0x10,0x3f}, // N
{0x1e,0x21,0x21,0x21,0x21,0x1e}, // O
{0x3f,0x09,0x09,0x09,0x09,0x06}, // P
{0x1e,0x21,0x29,0x31,0x21,0x1e}, // Q
{0x3f,0x09,0x09,0x09,0x19,0x26}, // R
{0x12,0x25,0x25,0x25,0x25,0x18}, // S
{0x01,0x01,0x01,0x3f,0x01,0x01}, // T
{0x1f,0x20,0x20,0x20,0x20,0x1f}, // U
{0x0f,0x10,0x20,0x20,0x10,0x0f}, // V
{0x1f,0x20,0x10,0x10,0x20,0x1f}, // W
{0x21,0x12,0x0c,0x0c,0x12,0x21}, // X
{0x01,0x02,0x0c,0x38,0x04,0x02}, // Y
{0x21,0x31,0x29,0x25,0x23,0x21}, // Z
{0x3f,0x21,0x00,0x00,0x00,0x00}, // [
{0x02,0x04,0x08,0x10,0x20,0x00}, // "\"
{0x21,0x3f,0x00,0x00,0x00,0x00}, // ]
{0x04,0x02,0x3f,0x02,0x04,0x00}, // ^
{0x40,0x40,0x40,0x40,0x40,0x40}, // _
{0x01,0x02,0x00,0x00,0x00,0x00}, // `
{0x10,0x30,0x2a,0x2a,0x3c,0x00}, // a
{0x3f,0x24,0x24,0x24,0x18,0x00}, // b
{0x0c,0x14,0x22,0x22,0x00,0x00}, // c
{0x18,0x24,0x24,0x24,0x3f,0x00}, // d
{0x1c,0x2c,0x2a,0x2a,0x24,0x00}, // e
{0x3e,0x05,0x01,0x00,0x00,0x00}, // f
{0x18,0x28,0xa4,0xa4,0x7c,0x00}, // g
{0x3f,0x04,0x04,0x0c,0x30,0x00}, // h
{0x24,0x3d,0x20,0x00,0x00,0x00}, // i
{0x20,0x40,0x40,0x3d,0x00,0x00}, // j
{0x3f,0x0c,0x12,0x20,0x00,0x00}, // k
{0x1f,0x20,0x20,0x00,0x00,0x00}, // l
{0x3e,0x02,0x3c,0x02,0x3c,0x00}, // m
{0x3e,0x02,0x02,0x02,0x3c,0x00}, // n
{0x0c,0x14,0x22,0x32,0x0c,0x00}, // o
{0xfc,0x24,0x24,0x24,0x18,0x00}, // p
{0x18,0x24,0x24,0x24,0xfc,0x80}, // q
{0x3c,0x04,0x02,0x02,0x00,0x00}, // r
{0x24,0x2c,0x2a,0x2a,0x10,0x00}, // s
{0x02,0x1f,0x22,0x20,0x00,0x00}, // t
{0x1e,0x20,0x20,0x20,0x1e,0x00}, // u
{0x06,0x18,0x20,0x18,0x06,0x00}, // v
{0x1e,0x30,0x1c,0x30,0x0e,0x00}, // w
{0x22,0x14,0x08,0x14,0x22,0x00}, // x
{0x0c,0x10,0xa0,0xa0,0x7c,0x00}, // y
{0x22,0x32,0x2a,0x26,0x22,0x22}, // z
{0x0c,0x3f,0x21,0x00,0x00,0x00}, // {
{0x3f,0x00,0x00,0x00,0x00,0x00}, // |
{0x21,0x3f,0x0c,0x00,0x00,0x00}, // }
{0x02,0x01,0x02,0x01,0x00,0x00}, // ~
{0x00,0x00,0x00,0x00,0x00,0x00}
};
} // f4ll_cpp

View file

@ -0,0 +1,193 @@
#ifndef __ili9341_H
#define __ili9341_H
#include <f4ll_cpp/strangeton.h>
#include <f4ll_cpp/dmahelper.h>
#include <inttypes.h>
namespace f4ll_cpp {
class Ili9341Fsmc : public Strangeton<Ili9341Fsmc>, private DmaHelper
{
public:
struct PixelPair {
uint8_t g0, r0, r1, b0, b1, g1;
};
Ili9341Fsmc(volatile uint16_t *reg, volatile uint16_t *ram,
DMA_TypeDef *dma, uint32_t dmaStream,
bool horizontal = true);
void SetScrollMode(bool on);
void FillRect(uint16_t color, bool async = true);
void FillRect(uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint16_t color, bool async = true);
uint16_t Width() { return m_width; }
uint16_t Height() { return m_height; }
uint8_t ChrHeight() { return CHRHEIGHT; }
uint8_t ChrWidth() { return CHRWIDTH; }
void SetCursor(uint16_t x, uint16_t y, uint16_t fgColor, uint16_t bgColor);
void SetCursor(uint16_t x, uint16_t y);
void PrintChar(char c, uint16_t x, uint16_t y, uint16_t fgColor, uint16_t bgColor);
void PrintChar(char c, bool transparent = false);
void Print(char const *str, uint8_t len = 0, bool transparent = false);
inline void WaitDmaIdle() { while(m_dmaEngineBusy); }
void Test();
static void HandleDmaIrq(Ili9341Fsmc *obj) { obj->HandleDmaIrq(); }
private:
inline void WriteCmd(uint16_t cmd) { *m_reg = cmd; }
inline void WriteCmd(uint16_t cmd, uint16_t param) { *m_reg = cmd; *m_ram = param; }
void WriteCmd(uint16_t cmd, std::initializer_list<const uint16_t> params);
void WriteCmd_(uint16_t cmd, uint16_t cnt, ...);
void SetRect(uint16_t x, uint16_t y, uint16_t width, uint16_t height);
void WritePixels(void *src, uint32_t count, bool increment, bool async = true);
void ReadGRam(PixelPair *dst, uint32_t count, bool async = true);
void ReadPixels(uint16_t *dst, uint32_t count);
void SetScrollOffset();
volatile uint16_t * const m_reg;
volatile uint16_t * const m_ram;
void HandleDmaIrq();
void SetupDmaSize(uint32_t size);
uint16_t AdjustY(uint16_t y) { return (m_scrollOffset + y) % m_height; }
volatile bool m_dmaEngineBusy = false;
uint32_t m_dmaRemainingPixels = 0;
uint16_t m_dmaColor = 0;
// initialized in the constructor
uint16_t const m_width;
uint16_t const m_height;
uint16_t m_rectX;
uint16_t m_rectY;
uint16_t m_rectWidth;
uint16_t m_rectHeight;
bool m_scrollMode = false;
uint16_t m_scrollOffset = 0;
uint16_t m_xPos = 0;
uint16_t m_yPos = 0;
uint16_t m_fgColor = ILI9341_WHITE;
uint16_t m_bgColor = ILI9341_BLACK;
enum Commands {
ILI9341_NOP = 0x00,
ILI9341_RESET = 0x01,
ILI9341_READ_DISPLAY_IDENTIFICATION_INFORMATION = 0x04,
ILI9341_READ_DISPLAY_STATUS = 0x09,
ILI9341_READ_DISPLAY_POWER_MODE = 0x0A,
ILI9341_READ_DISPLAY_MADCTL = 0x0B,
ILI9341_READ_DISPLAY_PIXEL_FORMAT = 0x0C,
ILI9341_READ_DISPLAY_IMAGE_FORMAT = 0x0D,
ILI9341_READ_DISPLAY_SIGNAL_MODE = 0x0E,
ILI9341_READ_DISPLAY_SELF_DIAGNOSTIC_RESULT = 0x0F,
ILI9341_ENTER_SLEEP_MODE = 0x10,
ILI9341_SLEEP_OUT = 0x11,
ILI9341_PARTIAL_MODE_ON = 0x12,
ILI9341_NORMAL_DISPLAY_MODE_ON = 0x13,
ILI9341_DISPLAY_INVERSION_OFF = 0x20,
ILI9341_DISPLAY_INVERSION_ON = 0x21,
ILI9341_GAMMA = 0x26,
ILI9341_DISPLAY_OFF = 0x28,
ILI9341_DISPLAY_ON = 0x29,
ILI9341_COLUMN_ADDR = 0x2A,
ILI9341_PAGE_ADDR = 0x2B,
ILI9341_GRAM = 0x2C,
ILI9341_COLOR_SET = 0x2D,
ILI9341_MEMORY_READ = 0x2E,
ILI9341_PARTIAL_AREA = 0x30,
ILI9341_VERTICAL_SCROLLING_DEFINITION = 0x33,
ILI9341_TEARING_EFFECT_LINE_OFF = 0x34,
ILI9341_TEARING_EFFECT_LINE_ON = 0x35,
ILI9341_MAC = 0x36,
ILI9341_VERTICAL_SCROLLING_START_ADDRESS = 0x37,
ILI9341_IDLE_MODE_OFF = 0x38,
ILI9341_IDLE_MODE_ON = 0x39,
ILI9341_PIXEL_FORMAT = 0x3A,
ILI9341_WMC = 0x3C,
ILI9341_RMC = 0x3E,
ILI9341_SET_TEAR_SCANLINE = 0x44,
ILI9341_WDB = 0x51,
ILI9341_READ_DISPLAY_BRIGHTNESS = 0x52,
ILI9341_WCD = 0x53,
ILI9341_READ_CTRL_DISPLAY = 0x54,
ILI9341_WCABC = 0x55,
ILI9341_RCABC = 0x56,
ILI9341_WCABCMB = 0x5E,
ILI9341_RCABCMB = 0x5F,
ILI9341_RGB_INTERFACE = 0xB0,
ILI9341_FRC = 0xB1,
ILI9341_FRAME_CTRL_NM = 0xB2,
ILI9341_FRAME_CTRL_IM = 0xB3,
ILI9341_FRAME_CTRL_PM = 0xB4,
ILI9341_BPC = 0xB5,
ILI9341_DFC = 0xB6,
ILI9341_ENTRY_MODE_SET = 0xB7,
ILI9341_BACKLIGHT_CONTROL_1 = 0xB8,
ILI9341_BACKLIGHT_CONTROL_2 = 0xB9,
ILI9341_BACKLIGHT_CONTROL_3 = 0xBA,
ILI9341_BACKLIGHT_CONTROL_4 = 0xBB,
ILI9341_BACKLIGHT_CONTROL_5 = 0xBC,
ILI9341_BACKLIGHT_CONTROL_6 = 0xBD,
ILI9341_BACKLIGHT_CONTROL_7 = 0xBE,
ILI9341_BACKLIGHT_CONTROL_8 = 0xBF,
ILI9341_POWER1 = 0xC0,
ILI9341_POWER2 = 0xC1,
ILI9341_VCOM1 = 0xC5,
ILI9341_VCOM2 = 0xC7,
ILI9341_POWERA = 0xCB,
ILI9341_POWERB = 0xCF,
ILI9341_READ_ID1 = 0xDA,
ILI9341_READ_ID2 = 0xDB,
ILI9341_READ_ID3 = 0xDC,
ILI9341_READ_ID4 = 0xD3,
ILI9341_PGAMMA = 0xE0,
ILI9341_NGAMMA = 0xE1,
ILI9341_DTCA = 0xE8,
ILI9341_DTCB = 0xEA,
ILI9341_POWER_SEQ = 0xED,
ILI9341_3GAMMA_EN = 0xF2,
ILI9341_INTERFACE = 0xF6,
ILI9341_PRC = 0xF7,
};
static const uint8_t CHRHEIGHT = 8; // SHOULD BE 8
static const uint8_t CHRWIDTH = 6;
static const uint8_t CHRCOUNT = 96;
static const uint8_t m_font[CHRCOUNT][CHRWIDTH];
uint16_t m_fontBkgBuffer[CHRHEIGHT][CHRWIDTH];
public:
enum Colors {
ILI9341_BLACK = 0x0000, /* 0, 0, 0 */
ILI9341_NAVY = 0x000F, /* 0, 0, 128 */
ILI9341_DARKGREEN = 0x03E0, /* 0, 128, 0 */
ILI9341_DARKCYAN = 0x03EF, /* 0, 128, 128 */
ILI9341_MAROON = 0x7800, /* 128, 0, 0 */
ILI9341_PURPLE = 0x780F, /* 128, 0, 128 */
ILI9341_OLIVE = 0x7BE0, /* 128, 128, 0 */
ILI9341_LIGHTGREY = 0xC618, /* 192, 192, 192 */
ILI9341_DARKGREY = 0x7BEF, /* 128, 128, 128 */
ILI9341_BLUE = 0x001F, /* 0, 0, 255 */
ILI9341_GREEN = 0x07E0, /* 0, 255, 0 */
ILI9341_CYAN = 0x07FF, /* 0, 255, 255 */
ILI9341_RED = 0xF800, /* 255, 0, 0 */
ILI9341_MAGENTA = 0xF81F, /* 255, 0, 255 */
ILI9341_YELLOW = 0xFFE0, /* 255, 255, 0 */
ILI9341_WHITE = 0xFFFF, /* 255, 255, 255 */
ILI9341_ORANGE = 0xFD20, /* 255, 165, 0 */
ILI9341_GREENYELLOW = 0xAFE5, /* 173, 255, 47 */
ILI9341_PINK = 0xF81F,
};
};
} // f4ll_cpp
#endif

View file

@ -0,0 +1,39 @@
/*
* memcpy_dma.c
*
* Created on: Oct 1, 2019
* Author: abody
*/
#include <f4ll_cpp/dmahelper.h>
#include <f4ll_cpp/memcpydma.h>
namespace f4ll_cpp {
MemcpyDma::MemcpyDma(DMA_TypeDef *dma, uint32_t stream) :
DmaHelper(dma, stream),
m_busy(false)
{
LL_DMA_EnableIT_TC(dma, stream);
}
void* MemcpyDma::Copy(void *dst, void const *src, size_t length)
{
while(m_busy);
LL_DMA_SetM2MSrcAddress(GetDma(), GetStream(), (uint32_t)src);
LL_DMA_SetM2MDstAddress(GetDma(), GetStream(), (uint32_t)dst);
LL_DMA_SetDataLength(GetDma(), GetStream(), (length+3)/4 );
m_busy = true;
LL_DMA_EnableStream(GetDma(), GetStream());
return dst;
}
void MemcpyDma::HandleDmaIrq(void)
{
if(*GetIsReg() & GetTcMask()) { // DMA transfer complete
*GetIfcReg() = GetTcMask();
LL_DMA_DisableStream(GetDma(), GetStream());
m_busy = false;
}
}
} // f4ll_cpp

View file

@ -0,0 +1,33 @@
/*
* memcpy_dma.h
*
* Created on: Oct 1, 2019
* Author: abody
*/
#ifndef MEMCPY_DMA_H_
#define MEMCPY_DMA_H_
#include <inttypes.h>
#include <platform/dma_ll.h>
#include <f4ll_cpp/dmahelper.h>
#include <f4ll_cpp/singleton.h>
namespace f4ll_cpp {
class MemcpyDma : public DmaHelper, public Singleton<MemcpyDma>
{
public:
MemcpyDma(DMA_TypeDef *dma, uint32_t stream);
void* Copy(void *dst, void const *src, size_t length);
static inline void HandleDmaIrq(void *param) { reinterpret_cast<MemcpyDma*>(param)->HandleDmaIrq(); }
private:
void HandleDmaIrq();
volatile bool m_busy;
};
} // namespace f4ll_cpp
#endif /* MEMCPY_DMA_H_ */

View file

@ -0,0 +1,286 @@
/*
* usart_handler.c
*
* Created on: Sep 16, 2019
* Author: abody
*/
#include <f4ll_cpp/memcpydma.h>
#include "f4ll_cpp/crcscheduler.h"
#include <f4ll_cpp/packetuart.h>
#include <string.h>
#include <platform/usart_ll.h>
#if defined(HAVE_DIAG)
#include "diag.h"
#endif
#ifndef MOCKABLE
#define MOCKABLE(x) x
#endif
#ifndef DIAG_RX_BUFFER_SWITCH
# define DIAG_RX_BUFFER_SWITCH(x)
#endif
#ifndef DIAG_INTERRUPT_IN
# define DIAG_INTERRUPT_IN()
#endif
#ifndef DIAG_INTERRUPT_OUT
# define DIAG_INTERRUPT_OUT()
#endif
#define STARTMARKER 0x95
namespace f4ll_cpp
{
static inline uint32_t RoundUpTo4(uint32_t inp)
{
return (inp + 3) & 0xfffc;
}
#ifndef USART_STATS_DISABLED
static inline void StatsIncOverrun(struct usart_stats *s) {
++s->overrun;
}
static inline void StatsIncHdrError(struct usart_stats *s, uint32_t hdr) {
++s->hdrError;
s->lastErrHdr = hdr;
}
static inline void StatsIncPayloadError(struct usart_stats *s, uint32_t pep1, uint32_t pep2) {
++s->payloadErrror;
s->pep1 = pep1;
s->pep2 = pep2;
}
static inline void StatsIncDmaError(struct usart_stats *s) {
++s->dmaError;
}
static inline void StatsIncRcvd(struct usart_stats *s) {
++s->rcvd;
}
static inline void StatsIncPremature_hdr(struct usart_stats *s) {
++s->premature_hdr;
}
static inline void StatsIncPremature_payload(struct usart_stats *s) {
++s->premature_payload;
}
static inline void StatsIncSent(struct usart_stats *s) {
++s->sent;
}
static inline void StatsAddSkiped(struct usart_stats *s, uint8_t cnt) {
s->skiped += s->rcvd > 2 ? cnt : 0;
}
#else // USART_STATS_DISABLED
#define StatsIncOverrun(x)
#define StatsIncHdrError(x,y)
#define StatsIncPayloadError(x,y,z)
#define StatsIncDmaError(x)
#define StatsIncRcvd(x)
#define StatsIncPremature_hdr(x)
#define StatsIncPremature_payload(x)
#define StatsIncSent(x)
#define StatsAddSkiped(x,y)
#endif // USART_STATS_DISABLED
PacketUart::PacketUart(
USART_TypeDef *uart, DMA_TypeDef *dma, uint32_t stream_rx, uint32_t stream_tx, CrcScheduler *crcScheduler,
PacketUart::pku_packetreceivedcallback_t packetReceivedCallback, void * packetReceivedCallbackParam)
: UartBase(uart, dma, stream_rx, stream_tx)
, m_crcScheduler(crcScheduler)
{
uint32_t status = uart->SR;
volatile uint32_t tmpreg = uart->DR; // clearing some of the error/status bits in the USART
(void) tmpreg;
(void) status;
txBuffer.busy = 0;
txBuffer.error = 0;
txBuffer.requestedLength = 0;
rxBuffers[0].busy = 0;
rxBuffers[1].busy = 0;
rxBuffers[0].error = 0;
rxBuffers[1].error = 0;
rxBuffers[0].requestedLength = 0;
rxBuffers[1].requestedLength = 0;
packetReceivedCallback = packetReceivedCallback;
packetReceivedCallbackParam = packetReceivedCallbackParam;
rxSerial = -1;
txSerial = 0;
activeRxBuf = 0;
m_crcScheduler->AttachTasks( &crcSlot, crcTasks, 2);
#ifndef USART_STATS_DISABLED
memset(&st->stats, 0, sizeof(st->stats));
#endif
LL_USART_EnableIT_IDLE(uart);
}
uint8_t* PacketUart::GetTxBuffer()
{
return txBuffer.packet.payload;
}
uint8_t PacketUart::CheckHeader(Packet *packet)
{
return packet->header.startByte == STARTMARKER && (packet->header.startByte ^ packet->header.serial ^ packet->header.payloadLength) == packet->header.hash;
}
uint8_t PacketUart::Post(uint8_t const *payload, uint8_t length, uint8_t waitForCrcQueue)
{
struct Buffer *buffer = &txBuffer;
uint8_t hash = STARTMARKER;
buffer->packet.header.startByte = STARTMARKER;
buffer->packet.header.serial = txSerial;
hash ^= txSerial++;
buffer->packet.header.payloadLength = length;
hash ^= length;
buffer->packet.header.hash = hash;
uint16_t payloadLength = RoundUpTo4(length);
if(payload)
memcpy(txBuffer.packet.payload, payload, length);
txBuffer.requestedLength = sizeof(struct Header) + payloadLength + sizeof(uint32_t); // +4 for the hash
txBuffer.busy = 1;
txBuffer.error = 0;
m_crcScheduler->Enqueue(&crcSlot, 0, &txBuffer.packet, sizeof(txBuffer.packet.header) + payloadLength,
NULL, (uint32_t*)(txBuffer.packet.payload + payloadLength));
while(waitForCrcQueue && m_crcScheduler->IsTaskQueued(&crcSlot, 0));
SetupTransmit(&txBuffer.packet, txBuffer.requestedLength);
StatsIncSent(&status->stats);
return 0;
}
void PacketUart::SetupReceive()
{
uint8_t packetIndex = activeRxBuf;
rxBuffers[packetIndex].requestedLength = sizeof(rxBuffers[packetIndex].packet);
UartBase::SetupReceive(&rxBuffers[packetIndex], sizeof(rxBuffers[packetIndex].packet));
}
void PacketUart::ConsumePacket(uint8_t packetIndex)
{
Buffer *buffer = &rxBuffers[packetIndex];
if(buffer->busy) {
if(buffer->error)
StatsIncPayloadError(&status->stats, Buffer->errorInfo, *(uint32_t*) (Buffer->packet.payload + RoundUpTo4(Buffer->packet.header.payloadLength)));
else {
uint8_t diff = buffer->packet.header.serial - rxSerial;
if(diff > 1)
StatsAddSkiped(&status->stats, diff - 1);
rxSerial = buffer->packet.header.serial;
}
}
buffer->busy = buffer->error = 0;
}
void PacketUart::HandleRxDmaIrq()
{
DIAG_INTERRUPT_IN();
StatsIncRcvd(&status->stats);
if(*m_rxDma.GetIsReg() & m_rxDma.GetTcMask()) {
*m_rxDma.GetIfcReg() = m_rxDma.GetTcMask();
if(CheckHeader(&rxBuffers[activeRxBuf].packet)) {
m_crcScheduler->Enqueue(&crcSlot, 1, &rxBuffers[activeRxBuf].packet,
RoundUpTo4(rxBuffers[activeRxBuf].packet.header.payloadLength) + sizeof(struct Header),
this, &rxBuffers[activeRxBuf]);
} else {
StatsIncHdrError(&status->stats, *(uint32_t*)&status->rxBuffers[status->activeRxBuf].packet.header);
rxBuffers[activeRxBuf].error = 1;
}
}
if(*m_rxDma.GetIsReg() & m_rxDma.GetTeMask()) {
*m_rxDma.GetIfcReg() = m_rxDma.GetTeMask();
rxBuffers[activeRxBuf].error = 1;
}
activeRxBuf ^= 1;
DIAG_RX_BUFFER_SWITCH(status->activeRxBuf);
if(rxBuffers[activeRxBuf].busy)
StatsIncOverrun(&status->stats);
SetupReceive();
DIAG_INTERRUPT_OUT();
}
void PacketUart::CrcCalculationCompleted(void *callbackParm, uint32_t calculatedCrc, uint8_t success)
{
struct Buffer *ub = (struct Buffer*) callbackParm;
if(!success)
ub->error = 1;
else if(*(uint32_t*) (ub->packet.payload + RoundUpTo4(ub->packet.header.payloadLength)) == calculatedCrc)
ub->busy = 1;
else {
ub->error = ub->busy = 1;
ub->errorInfo = calculatedCrc;
}
if(packetReceivedCallback)
packetReceivedCallback(packetReceivedCallbackParam, ub);
}
void PacketUart::HandleTxDmaIrq()
{
DIAG_INTERRUPT_IN();
if(*m_txDma.GetIsReg() & m_txDma.GetTcMask()) { // DMA transfer complete
*m_txDma.GetIfcReg() = m_txDma.GetTcMask();
LL_USART_EnableIT_TC(m_uart);
LL_DMA_DisableStream(m_txDma.GetDma(), m_txDma.GetStream());
}
if(*m_txDma.GetIsReg() & m_txDma.GetTeMask()) {
*m_txDma.GetIfcReg() = m_txDma.GetTeMask();
txBuffer.error = 1;
LL_USART_EnableIT_TC(m_uart);
LL_DMA_DisableStream(m_txDma.GetDma(), m_txDma.GetStream());
StatsIncDmaError(&status->stats);
}
if(*m_txDma.GetIsReg() & m_txDma.GetFeMask())
*m_txDma.GetIfcReg() = m_txDma.GetFeMask();
if(*m_txDma.GetIsReg() & m_txDma.GetHtMask())
*m_txDma.GetIfcReg() = m_txDma.GetHtMask();
if(*m_txDma.GetIsReg() & m_txDma.GetDmeMask())
*m_txDma.GetIfcReg() = m_txDma.GetDmeMask();
DIAG_INTERRUPT_OUT();
}
void PacketUart::HandleUsartIrq()
{
DIAG_INTERRUPT_IN();
if(LL_USART_IsActiveFlag_IDLE(m_uart) && LL_USART_IsEnabledIT_IDLE(m_uart)) { // receiver idle
LL_USART_ClearFlag_IDLE(m_uart);
uint16_t rcvdLen = rxBuffers[activeRxBuf].requestedLength - LL_DMA_GetDataLength(m_rxDma.GetDma(), m_rxDma.GetStream());
if(rcvdLen >= sizeof(struct Header)) {
if(CheckHeader(&rxBuffers[activeRxBuf].packet)) {
if(rcvdLen >= sizeof(struct Header) + RoundUpTo4(rxBuffers[activeRxBuf].packet.header.payloadLength) + sizeof(uint32_t))
LL_DMA_DisableStream(m_rxDma.GetDma(), m_rxDma.GetStream());
else
StatsIncPremature_payload(&stats);
} else {
rxBuffers[activeRxBuf].error = 1;
rxBuffers[activeRxBuf].busy = 1;
LL_DMA_DisableStream(m_rxDma.GetDma(), m_rxDma.GetStream());
}
} else
StatsIncPremature_hdr(&status->stats);
}
if(LL_USART_IsActiveFlag_TC(m_uart) && LL_USART_IsEnabledIT_TC(m_uart)) { // transmission complete
LL_USART_DisableIT_TC(m_uart);
LL_USART_DisableDirectionTx(m_uart); // enforcing an idle frame
LL_USART_EnableDirectionTx(m_uart);
txBuffer.busy = 0;
}
DIAG_INTERRUPT_OUT();
}
} // f4ll_cpp

View file

@ -0,0 +1,107 @@
/*
* usart_handler.h
*
* Created on: Sep 16, 2019
* Author: abody
*/
#ifndef USART_HANDLER_H_
#define USART_HANDLER_H_
#include <inttypes.h>
#include <platform/usart_ll.h>
#include <f4ll_cpp/uartbase.h>
#define USART_STATS_DISABLED
namespace f4ll_cpp {
class PacketUart : public UartBase, public CrcScheduler::ICrcCallback
{
public:
struct Buffer;
struct IPacketUsartCallback {
virtual void PacketReceived(void *userParam, Buffer *buffer) = 0;
};
struct Stats {
uint32_t overrun;
uint32_t hdrError;
uint32_t lastErrHdr;
uint32_t payloadErrror;
uint32_t pep1, pep2;
uint32_t dmaError;
uint32_t rcvd;
uint32_t premature_hdr;
uint32_t premature_payload;
uint32_t sent;
uint32_t skiped;
};
struct Header {
uint8_t startByte;
uint8_t serial;
uint8_t payloadLength;
uint8_t hash;
};
struct Packet {
struct Header header;
//!!! should start on word offset !!!
uint8_t payload[256+sizeof(uint32_t)]; // extra room for crc32
} __attribute__((aligned));
struct Buffer {
Packet packet;
//transfer area ends here
volatile uint8_t busy;
volatile uint8_t error;
uint16_t requestedLength;
uint32_t errorInfo;
};
typedef void (*pku_packetreceivedcallback_t)(void *userParam, Buffer *Buffer);
PacketUart(
USART_TypeDef *uart, DMA_TypeDef *dma, uint32_t stream_rx, uint32_t stream_tx, CrcScheduler *crcScheduler,
PacketUart::pku_packetreceivedcallback_t packetReceivedCallback, void * packetReceivedCallbackParam);
uint8_t* GetTxBuffer();
uint8_t Post(uint8_t const *payload, uint8_t length, uint8_t waitForCrcQueue);
void SetupReceive();
void ConsumePacket(uint8_t packetIndex);
static void HandleRxDmaIrq(void* param) { reinterpret_cast<PacketUart*>(param)->HandleRxDmaIrq(); }
static void HandleTxDmaIrq(void* param) { reinterpret_cast<PacketUart*>(param)->HandleTxDmaIrq(); }
static void HandleUsartIrq(void* param) { reinterpret_cast<PacketUart*>(param)->HandleUsartIrq(); }
uint8_t CheckHeader(struct Packet *packet);
protected:
private:
void HandleRxDmaIrq();
void HandleTxDmaIrq();
void HandleUsartIrq();
virtual void CrcCalculationCompleted(void*, uint32_t, uint8_t);
CrcScheduler *m_crcScheduler;
CrcScheduler::crcslot_t crcSlot;
CrcScheduler::crctask_t crcTasks[2];
uint8_t rxSerial;
uint8_t txSerial;
Stats stats;
uint8_t activeRxBuf;
pku_packetreceivedcallback_t packetReceivedCallback;
void *packetReceivedCallbackParam;
Buffer txBuffer;
Buffer rxBuffers[2];
};
} // f4ll_cpp
#endif /* UART_HANDLER_H_ */

View file

@ -0,0 +1,173 @@
/*
* interrupt.h
*
* Created on: Aug 29, 2019
* Author: abody
*/
#ifndef CONSOLEHANDLER_H_
#define CONSOLEHANDLER_H_
#include <cstring>
#include "usart.h"
#include <f4ll_cpp/dmahelper.h>
#include <f4ll_cpp/uartbase.h>
namespace f4ll_cpp {
template<unsigned int bufSize> class SerialConsole : protected UartBase
{
public:
struct Buffer {
volatile bool busy = false;
volatile bool error = false;
uint8_t len;
char buffer[bufSize];
};
struct ISerialConsoleCallback {
virtual void LineReceived(void *userParam, Buffer *buffer) = 0;
virtual void TransmissionComplete(void *userParam, Buffer *buffer) = 0;
};
SerialConsole(USART_TypeDef *uart, DMA_TypeDef *dma, uint32_t stream_rx, uint32_t stream_tx,
ISerialConsoleCallback *callback, void *callbackUserParam);
void Send(char const *buffer, uint8_t length = 0);
void SendLine(char const *buffer, uint8_t length = 0);
void HandleRxDmaIrq();
void HandleTxDmaIrq();
void HandleUsartIrq();
private:
void SetupTransmit(void *buffer, uint16_t length);
bool m_activeRxBuffer = false;
Buffer m_rxBuffers[2];
Buffer m_txBuffer;
ISerialConsoleCallback *m_callback;
void *m_callbackUserParam;
};
template<unsigned int bufSize> SerialConsole<bufSize>::SerialConsole(
USART_TypeDef *uart, DMA_TypeDef *dma, uint32_t stream_rx, uint32_t stream_tx,
ISerialConsoleCallback *callback, void *callbackUserParam
)
: UartBase(uart, dma, stream_rx, stream_tx)
, m_callback(callback), m_callbackUserParam(callbackUserParam)
{
LL_USART_EnableIT_IDLE(uart);
SetupReceive(m_rxBuffers[m_activeRxBuffer].buffer, bufSize);
}
template<unsigned int bufSize> void SerialConsole<bufSize>::SetupTransmit(void *buffer, uint16_t length)
{
m_txBuffer.busy = true;
UartBase::SetupTransmit(buffer, length);
}
template<unsigned int bufSize> void SerialConsole<bufSize>::HandleRxDmaIrq()
{
if(*m_rxDma.GetIsReg() & m_rxDma.GetTcMask()) {
*m_rxDma.GetIfcReg() = m_rxDma.GetTcMask();
m_rxBuffers[m_activeRxBuffer].busy = true;
if(m_callback)
m_callback->LineReceived(m_callbackUserParam, &m_rxBuffers[m_activeRxBuffer]);
}
if(*m_rxDma.GetIsReg() & m_rxDma.GetTeMask()) {
*m_rxDma.GetIfcReg() = m_rxDma.GetTeMask();
}
m_activeRxBuffer = !m_activeRxBuffer;
SetupReceive(m_rxBuffers[m_activeRxBuffer].buffer, bufSize);
}
template<unsigned int bufSize> void SerialConsole<bufSize>::HandleTxDmaIrq()
{
if(*m_txDma.GetIsReg() & m_txDma.GetTcMask()) { // DMA transfer complete
*m_txDma.GetIfcReg() = m_txDma.GetTcMask();
LL_USART_EnableIT_TC(m_uart);
LL_DMA_DisableStream(m_txDma.GetDma(), m_txDma.GetStream());
}
if(*m_txDma.GetIsReg() & m_txDma.GetTeMask()) {
*m_txDma.GetIfcReg() = m_txDma.GetTeMask();
m_txBuffer.error = true;
LL_USART_EnableIT_TC(m_uart);
LL_DMA_DisableStream(m_txDma.GetDma(), m_txDma.GetStream());
}
}
template<unsigned int bufSize> void SerialConsole<bufSize>::HandleUsartIrq()
{
if(LL_USART_IsActiveFlag_IDLE(m_uart) && LL_USART_IsEnabledIT_IDLE(m_uart)) { // receiver idle
// we assume that new line marker will arrive without an idle cycle even if it is CRLF
LL_USART_ClearFlag_IDLE(m_uart);
uint16_t rcvdLen = bufSize - LL_DMA_GetDataLength(m_rxDma.GetDma(), m_rxDma.GetStream());
if(rcvdLen ) {
bool newLine = false;;
do {
auto lastChar = m_rxBuffers[m_activeRxBuffer].buffer[rcvdLen-1];
if( lastChar == '\r' || lastChar == '\n')
newLine = true;
else
break;
} while(--rcvdLen);
if(newLine) {
m_rxBuffers[m_activeRxBuffer].buffer[rcvdLen] = 0;
m_rxBuffers[m_activeRxBuffer].len = rcvdLen;
LL_DMA_DisableStream(m_rxDma.GetDma(), m_rxDma.GetStream());
}
}
}
if(LL_USART_IsActiveFlag_TC(m_uart) && LL_USART_IsEnabledIT_TC(m_uart)) { // transmission complete
LL_USART_DisableIT_TC(m_uart);
LL_USART_DisableDirectionTx(m_uart); // enforcing an idle frame
LL_USART_EnableDirectionTx(m_uart);
m_txBuffer.busy = false;
if(m_callback)
m_callback->TransmissionComplete(m_callbackUserParam, &m_txBuffer);
}
}
template<unsigned int bufSize> void SerialConsole<bufSize>::Send(char const *buffer, uint8_t length)
{
if(!length) {
auto computedLength = strlen(buffer);
if(computedLength <= (uint8_t)-1)
length = computedLength;
}
if(length) {
while( m_txBuffer.busy );
memcpy(m_txBuffer.buffer, buffer, length);
SetupTransmit(m_txBuffer.buffer, length);
}
}
template<unsigned int bufSize> void SerialConsole<bufSize>::SendLine(char const *buffer, uint8_t length)
{
if(!length) {
auto computedLength = strlen(buffer);
if(computedLength <= (uint8_t)-1)
length = computedLength;
}
if(length) {
while( m_txBuffer.busy );
memcpy(m_txBuffer.buffer, buffer, length);
if(m_txBuffer.buffer[length-1] != '\n') {
m_txBuffer.buffer[length++] = '\r';
m_txBuffer.buffer[length++] = '\n';
}
SetupTransmit(m_txBuffer.buffer, length);
}
}
} // f4ll_cpp
#endif /* CONSOLEHANDLER_H_ */

View file

@ -0,0 +1,34 @@
/*
* singleton.h
*
* Created on: Sep 11, 2019
* Author: compi
*/
#ifndef SINGLETON_H_
#define SINGLETON_H_
#include <utility>
namespace f4ll_cpp {
template<typename T> class Singleton {
public:
static T &Instance() {
static T instance;
return instance;
}
protected:
Singleton() = default;
Singleton(const Singleton &) = delete;
Singleton &operator=(const Singleton &) = delete;
virtual ~Singleton() = default;
static T *m_instance;
};
template<typename T> T* Singleton<T>::m_instance = nullptr;
} // f4ll_cpp
#endif /* SINGLETON_H_ */

View file

@ -0,0 +1,39 @@
/*
* singleton.h
*
* Created on: Sep 11, 2019
* Author: compi
*/
#ifndef SINGLETON_H_
#define SINGLETON_H_
#include <utility>
namespace f4ll_cpp {
template<typename T> class Strangeton {
public:
static T &Instance() {
return *m_instance;
}
template<typename ... Args> static T &Init(Args &&... args) {
static T instance{ std::forward<Args>(args)... };
if(!m_instance)
m_instance = &instance;
return instance;
}
protected:
Strangeton() = default;
Strangeton(const Strangeton &) = delete;
Strangeton &operator=(const Strangeton &) = delete;
virtual ~Strangeton() = default;
static T *m_instance;
};
template<typename T> T* Strangeton<T>::m_instance = nullptr;
} // f4ll_cpp
#endif /* SINGLETON_H_ */

View file

@ -0,0 +1,49 @@
/*
* UartBase.cpp
*
* Created on: Feb 4, 2020
* Author: abody
*/
#include <f4ll_cpp/uartbase.h>
namespace f4ll_cpp {
UartBase::UartBase(USART_TypeDef *uart, DMA_TypeDef *dma, uint32_t stream_rx, uint32_t stream_tx)
: m_uart(uart)
, m_rxDma(dma, stream_rx)
, m_txDma(dma, stream_tx)
{
*m_rxDma.GetIfcReg() =
m_rxDma.GetTcMask() | m_rxDma.GetHtMask() |
m_rxDma.GetTeMask() | m_rxDma.GetFeMask() | m_rxDma.GetDmeMask();
*m_txDma.GetIfcReg() =
m_txDma.GetTcMask() | m_txDma.GetHtMask() |
m_txDma.GetTeMask() | m_txDma.GetFeMask() | m_txDma.GetDmeMask();
LL_DMA_EnableIT_TC(dma, stream_rx);
LL_DMA_EnableIT_TE(dma, stream_rx);
LL_DMA_EnableIT_TC(dma, stream_tx);
LL_DMA_EnableIT_TE(dma, stream_tx);
}
void UartBase::SetupReceive(void *buffer, uint16_t length)
{
LL_DMA_ConfigAddresses(m_rxDma.GetDma(), m_rxDma.GetStream(), LL_USART_DMA_GetRegAddr(m_uart),
(uint32_t)buffer, LL_DMA_DIRECTION_PERIPH_TO_MEMORY);
LL_DMA_SetDataLength(m_rxDma.GetDma(), m_rxDma.GetStream(), length); // payload already have extra room for hash
LL_USART_EnableDMAReq_RX(m_uart);
LL_USART_ClearFlag_ORE(m_uart);
LL_DMA_EnableStream(m_rxDma.GetDma(), m_rxDma.GetStream());
}
void UartBase::SetupTransmit(void *buffer, uint16_t length)
{
LL_DMA_ConfigAddresses(m_txDma.GetDma(), m_txDma.GetStream(), (uint32_t)buffer, LL_USART_DMA_GetRegAddr(m_uart), LL_DMA_DIRECTION_MEMORY_TO_PERIPH);
LL_DMA_SetDataLength(m_txDma.GetDma(), m_txDma.GetStream(), length);
LL_USART_EnableDMAReq_TX(m_uart);
LL_DMA_EnableStream(m_txDma.GetDma(), m_txDma.GetStream());
}
} // f4ll_cpp

View file

@ -0,0 +1,31 @@
/*
* UartBase.h
*
* Created on: Feb 4, 2020
* Author: abody
*/
#ifndef F4LL_CPP_UARTBASE_H_
#define F4LL_CPP_UARTBASE_H_
#include <platform/usart_ll.h>
#include <f4ll_cpp/dmahelper.h>
namespace f4ll_cpp {
class UartBase
{
public:
UartBase() = delete;
protected:
UartBase(USART_TypeDef *uart, DMA_TypeDef *dma, uint32_t stream_rx, uint32_t stream_tx);
void SetupTransmit(void *buffer, uint16_t length);
void SetupReceive(void *buffer, uint16_t length);
USART_TypeDef *m_uart;
DmaHelper m_rxDma;
DmaHelper m_txDma;
};
} // f4ll_cpp
#endif /* F4LL_CPP_UARTBASE_H_ */

36
components/fsl/task.h Normal file
View file

@ -0,0 +1,36 @@
/*
* task.h
*
* Created on: Oct 29, 2021
* Author: compi
*/
#ifndef FSL_TASK_H_
#define FSL_TASK_H_
#include <FreeRTOS.h>
#include <task.h> // FreeRTOS
#include <semphr.h> // FreeRTOS
namespace fsl {
template<typename T, uint32_t stackSize> class Task {
public:
Task(UBaseType_t priority) : m_priority(priority) {}
void Start(SemaphoreHandle_t doneSem = nullptr, bool waitForInit = false) {
m_handle = xTaskCreateStatic(T::TaskFn, getName(), sizeof(m_stack)/sizeof(m_stack[0]),
this, m_priority, m_stack, &m_tcb);
}
virtual ~Task() {};
virtual char const * getName() = 0;
private:
TaskHandle_t m_handle;
UBaseType_t m_priority;
StaticTask_t m_tcb;
StackType_t m_stack[stackSize];
};
} /* namespace fsl */
#endif /* FSL_TASK_H_ */