Kinda works
This commit is contained in:
parent
f3d345e2e3
commit
662a7a9b12
40 changed files with 2851 additions and 26 deletions
194
components/f4ll_cpp/crcscheduler.cpp
Normal file
194
components/f4ll_cpp/crcscheduler.cpp
Normal 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
|
72
components/f4ll_cpp/crcscheduler.h
Normal file
72
components/f4ll_cpp/crcscheduler.h
Normal 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_ */
|
86
components/f4ll_cpp/dmahelper.cpp
Normal file
86
components/f4ll_cpp/dmahelper.cpp
Normal 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
|
57
components/f4ll_cpp/dmahelper.h
Normal file
57
components/f4ll_cpp/dmahelper.h
Normal 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_ */
|
404
components/f4ll_cpp/ili9341.cpp
Normal file
404
components/f4ll_cpp/ili9341.cpp
Normal 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
|
193
components/f4ll_cpp/ili9341.h
Normal file
193
components/f4ll_cpp/ili9341.h
Normal 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
|
39
components/f4ll_cpp/memcpydma.cpp
Normal file
39
components/f4ll_cpp/memcpydma.cpp
Normal 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
|
33
components/f4ll_cpp/memcpydma.h
Normal file
33
components/f4ll_cpp/memcpydma.h
Normal 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_ */
|
286
components/f4ll_cpp/packetuart.cpp
Normal file
286
components/f4ll_cpp/packetuart.cpp
Normal 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
|
107
components/f4ll_cpp/packetuart.h
Normal file
107
components/f4ll_cpp/packetuart.h
Normal 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_ */
|
173
components/f4ll_cpp/serialconsole.h
Normal file
173
components/f4ll_cpp/serialconsole.h
Normal 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_ */
|
34
components/f4ll_cpp/singleton.h
Normal file
34
components/f4ll_cpp/singleton.h
Normal 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_ */
|
39
components/f4ll_cpp/strangeton.h
Normal file
39
components/f4ll_cpp/strangeton.h
Normal 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_ */
|
49
components/f4ll_cpp/uartbase.cpp
Normal file
49
components/f4ll_cpp/uartbase.cpp
Normal 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
|
31
components/f4ll_cpp/uartbase.h
Normal file
31
components/f4ll_cpp/uartbase.h
Normal 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
36
components/fsl/task.h
Normal 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_ */
|
Loading…
Add table
Add a link
Reference in a new issue