Divided USART communication into core and protocol classes

This commit is contained in:
Attila Body 2019-11-07 08:33:48 +01:00
parent 9ff4e76623
commit f0c2ad69c9
7 changed files with 287 additions and 121 deletions

View file

@ -223,7 +223,7 @@ void SysTick_Handler(void)
void DMA1_Stream1_IRQHandler(void)
{
/* USER CODE BEGIN DMA1_Stream1_IRQn 0 */
f4ll::LL_HsUsart::HandleRxDmaIrq(g_usarts[USART3_OFFSET]);
f4ll::LL_UsartCore::HandleRxDmaIrq(g_usarts[USART3_OFFSET]);
/* USER CODE END DMA1_Stream1_IRQn 0 */
/* USER CODE BEGIN DMA1_Stream1_IRQn 1 */

View file

@ -46,7 +46,8 @@ void _PrintStats(char *buffer, uint8_t id, f4ll::LL_HsUsart &handler, USART_Type
buffer += uitohex(buffer, stats.pep1, 8);
buffer += strcpy_ex(buffer,",0x");
buffer += uitohex(buffer, stats.pep2, 8);
ADDINFO(buffer, " de: ", stats.dmaError);
ADDINFO(buffer, " rde: ", stats.rxDmaError);
ADDINFO(buffer, " tde: ", stats.txDmaError);
ADDINFO(buffer, " pmh: ", stats.premature_hdr);
ADDINFO(buffer, " pmp: ", stats.premature_payload);
buffer += strcpy_ex(buffer, "\r\n");

View file

@ -28,6 +28,18 @@ public:
inline uint32_t GetHtMask() const { return m_HTMasks[m_stream]; }
inline uint32_t GetTcMask() const { return m_TCMasks[m_stream]; }
inline bool IsEnabledIt_HT() { return LL_DMA_IsEnabledIT_HT(m_dma, m_stream) != 0; }
inline bool IsEnabledIt_TE() { return LL_DMA_IsEnabledIT_TE(m_dma, m_stream) != 0; }
inline bool IsEnabledIt_TC() { return LL_DMA_IsEnabledIT_TC(m_dma, m_stream) != 0; }
inline bool IsEnabledIt_DME() { return LL_DMA_IsEnabledIT_DME(m_dma, m_stream) != 0; }
inline bool IsEnabledIt_FE() { return LL_DMA_IsEnabledIT_FE(m_dma, m_stream) != 0; }
enum class DmaErrorType {
Transfer,
DirectMode,
Fifo
};
private:
DMA_TypeDef *m_dma;
uint32_t m_stream;

View file

@ -14,19 +14,11 @@ template<typename T> static inline T RoundUpTo4(T input)
return (input + 3) & (((T)-1) - 3);
}
LL_HsUsart::LL_HsUsart(USART_TypeDef *usart, DMA_TypeDef *dma, uint32_t streamRx, uint32_t streamTx)
: m_usart(usart)
, m_rxDma(dma, streamRx)
, m_txDma(dma, streamTx)
: LL_UsartCore(usart, dma, streamRx, streamTx)
{
LL_CrcHandler::Instance().AttachSlot(m_crcSlot);
LL_DMA_EnableIT_TC(dma, streamRx);
LL_DMA_EnableIT_TE(dma, streamRx);
LL_DMA_EnableIT_TC(dma, streamTx);
LL_DMA_EnableIT_TE(dma, streamTx);
LL_USART_EnableIT_IDLE(usart);
memset(&m_stats, 0, sizeof(m_stats));
}
@ -119,11 +111,7 @@ void LL_HsUsart::PostPacket(uint8_t const *payload, uint8_t length, bool waitFor
while(waitForCrcQueue && LL_CrcHandler::Instance().IsQueued(m_crcSlot, 0));
LL_DMA_ConfigAddresses(m_txDma.GetDma(), m_txDma.GetStream(), reinterpret_cast<uint32_t>(&m_txBuffer.packet),
LL_USART_DMA_GetRegAddr(m_usart), LL_DMA_DIRECTION_MEMORY_TO_PERIPH);
LL_DMA_SetDataLength(m_txDma.GetDma(), m_txDma.GetStream(), m_txBuffer.requestedLength);
LL_USART_EnableDMAReq_TX(m_usart);
LL_DMA_EnableStream(m_txDma.GetDma(), m_txDma.GetStream());
SetupTransmit(&m_txBuffer.packet, m_txBuffer.requestedLength);
++m_stats.sent;
}
@ -131,22 +119,13 @@ void LL_HsUsart::PostPacket(uint8_t const *payload, uint8_t length, bool waitFor
void LL_HsUsart::SetupReceive()
{
int packetIndex = m_rxBufferSelector;
LL_DMA_ConfigAddresses(m_rxDma.GetDma(), m_rxDma.GetStream(), LL_USART_DMA_GetRegAddr(m_usart),
reinterpret_cast<uint32_t>(&m_rxBuffers[packetIndex]), LL_DMA_DIRECTION_PERIPH_TO_MEMORY);
m_rxBuffers[packetIndex].requestedLength = sizeof(m_rxBuffers[packetIndex].packet);
LL_DMA_SetDataLength(m_rxDma.GetDma(), m_rxDma.GetStream(), m_rxBuffers[packetIndex].requestedLength); // payload already have extra room for hash
LL_USART_EnableDMAReq_RX(m_usart);
LL_USART_ClearFlag_ORE(m_usart);
LL_DMA_EnableStream(m_rxDma.GetDma(), m_rxDma.GetStream());
m_rxBuffers[m_rxBufferSelector].requestedLength = sizeof(m_rxBuffers[m_rxBufferSelector].packet);
LL_UsartCore::SetupReceive(&m_rxBuffers[m_rxBufferSelector], sizeof(m_rxBuffers[m_rxBufferSelector].packet));
}
void LL_HsUsart::UsartIrq(void)
void LL_HsUsart::ReceiverIdle(void)
{
if(LL_USART_IsActiveFlag_IDLE(m_usart) && LL_USART_IsEnabledIT_IDLE(m_usart)) { // receiver idle
LL_USART_ClearFlag_IDLE(m_usart);
uint16_t rcvdLen = m_rxBuffers[m_rxBufferSelector].requestedLength - LL_DMA_GetDataLength(m_rxDma.GetDma(), m_rxDma.GetStream());
if(rcvdLen >= sizeof(PacketHeader)) {
if(CheckHeader(m_rxBuffers[m_rxBufferSelector].packet.header)) {
@ -163,20 +142,18 @@ void LL_HsUsart::UsartIrq(void)
} else
++m_stats.premature_hdr;
}
else if(LL_USART_IsActiveFlag_TC(m_usart) && LL_USART_IsEnabledIT_TC(m_usart)) { // transmission complete
LL_USART_DisableIT_TC(m_usart);
void LL_HsUsart::TransmissionComplete(void)
{
LL_USART_DisableDirectionTx(m_usart); // enforcing an idle frame
LL_USART_EnableDirectionTx(m_usart);
m_txBuffer.busy = 0;
}
}
void LL_HsUsart::RxDmaIrq()
void LL_HsUsart::RxDmaTransferComplete(void)
{
++m_stats.rcvd;
if(*m_rxDma.GetIsReg() & m_rxDma.GetTcMask()) {
*m_rxDma.GetIfcReg() = m_rxDma.GetTcMask();
if(CheckHeader(m_rxBuffers[m_rxBufferSelector].packet.header))
LL_CrcHandler::Instance().Enqueue(m_crcSlot, 1,
&m_rxBuffers[m_rxBufferSelector].packet,
@ -186,12 +163,43 @@ void LL_HsUsart::RxDmaIrq()
++m_stats.hdrError;
m_rxBuffers[m_rxBufferSelector].error = true;
}
} else if(*m_rxDma.GetIsReg() & m_rxDma.GetTeMask()) {
*m_rxDma.GetIfcReg() = m_rxDma.GetTeMask();
m_rxBuffers[m_rxBufferSelector].error = 1;
++m_stats.dmaError;
SwitchRxBuffers();
}
void LL_HsUsart::RxDmaHalfTransfer(void)
{
}
void LL_HsUsart::RxDmaError(LL_DmaHelper::DmaErrorType reason)
{
m_rxBuffers[m_rxBufferSelector].error = 1;
++m_stats.rxDmaError;
SwitchRxBuffers();
}
void LL_HsUsart::TxDmaTransferComplete(void)
{
LL_USART_EnableIT_TC(m_usart);
LL_DMA_DisableStream(m_txDma.GetDma(), m_txDma.GetStream());
}
void LL_HsUsart::TxDmaHalfTransfer(void)
{
}
void LL_HsUsart::TxDmaError(LL_DmaHelper::DmaErrorType reason)
{
m_txBuffer.error = 1;
++m_stats.txDmaError;
}
void LL_HsUsart::SwitchRxBuffers(void)
{
++m_stats.rcvd;
m_rxBufferSelector = !m_rxBufferSelector;
if(m_rxBuffers[m_rxBufferSelector].busy)
@ -226,25 +234,4 @@ void LL_HsUsart::CrcFailed(uintptr_t callbackParam, uint32_t crc, int prio)
}
void LL_HsUsart::TxDmaIrq()
{
if(*m_txDma.GetIsReg() & m_txDma.GetTcMask()) { // DMA transfer complete
*m_txDma.GetIfcReg() = m_txDma.GetTcMask();
LL_USART_EnableIT_TC(m_usart);
LL_DMA_DisableStream(m_txDma.GetDma(), m_txDma.GetStream());
}
else if(*m_txDma.GetIsReg() & m_txDma.GetTeMask()) {
*m_txDma.GetIfcReg() = m_txDma.GetTeMask();
m_txBuffer.error = 1;
++m_stats.dmaError;
}
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();
}
} // namespace f4ll

View file

@ -8,13 +8,14 @@
#ifndef LL_HSUSART_H_
#define LL_HSUSART_H_
#include <platform/usart_ll.h>
#include <ll_usartcore.h>
#include <ll_crchandler.h>
namespace f4ll {
struct DMAINFO;
class LL_HsUsart : public LL_CrcHandler::ICallback
class LL_HsUsart : public LL_CrcHandler::ICallback, public LL_UsartCore
{
public:
LL_HsUsart(USART_TypeDef *usart, DMA_TypeDef *dma, uint32_t stream_rx, uint32_t stream_tx);
@ -32,16 +33,18 @@ public:
} __attribute__((aligned));
struct Stats {
uint32_t overrun;
uint32_t hdrError;
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;
uint32_t overrun = 0;
uint32_t hdrError = 0;
uint32_t payloadErrror = 0;
uint32_t pep1 = 0;
uint32_t pep2 = 0;
uint32_t rxDmaError = 0;
uint32_t txDmaError = 0;
uint32_t rcvd = 0;
uint32_t premature_hdr = 0;
uint32_t premature_payload = 0;
uint32_t sent = 0;
uint32_t skiped = 0;
};
struct IHsUsartCallback {
@ -52,35 +55,34 @@ public:
virtual void CrcSucceeded(uintptr_t callbackParam, uint32_t crc, int prio);
virtual void CrcFailed(uintptr_t callbackParam, uint32_t crc, int prio);
// LL_UsartCore pure virtual function implementations
virtual void ReceiverIdle(void);
virtual void TransmissionComplete(void);
virtual void RxDmaTransferComplete(void);
virtual void RxDmaHalfTransfer(void);
virtual void RxDmaError(LL_DmaHelper::DmaErrorType reason);
virtual void TxDmaTransferComplete(void);
virtual void TxDmaHalfTransfer(void);
virtual void TxDmaError(LL_DmaHelper::DmaErrorType reason);
void PostPacket(uint8_t const *payload, uint8_t length, bool waitForCrcQueue = true);
void SetupReceive(void);
void RxProcessed(bool second);
uint8_t* GetTxPacketBuffer(void);
USART_TypeDef* GetUsart(void);
Stats const & GetStats();
bool IsTxBusy();
bool IsTxFailed();
Stats const & GetStats(void);
bool IsTxBusy(void);
bool IsTxFailed(void);
bool IsRxBusy(bool second);
bool IsRxFailed(bool second);
void SetCallback(IHsUsartCallback* callback, uintptr_t callbackParam);
static inline void HandleUsartIrq(LL_HsUsart *obj) {
obj->UsartIrq();
}
static inline void HandleRxDmaIrq(LL_HsUsart *obj) {
obj->RxDmaIrq();
}
static inline void HandleTxDmaIrq(LL_HsUsart *obj) {
obj->TxDmaIrq();
}
private:
void BuildHeader(Packet &packet, uint8_t serialNo, uint8_t length);
bool CheckHeader(PacketHeader &header);
void UsartIrq(void);
void RxDmaIrq(void);
void TxDmaIrq(void);
void SwitchRxBuffers(void);
struct Buffer {
Packet packet;
@ -93,9 +95,6 @@ private:
static const uint8_t STARTMARKER = 0x95;
USART_TypeDef *m_usart;
LL_DmaHelper m_rxDma;
LL_DmaHelper m_txDma;
uint8_t m_rxSerialNo = -1;
uint8_t m_txSerialNo = -1;
Stats m_stats;

116
lib/ll_usartcore.cpp Normal file
View file

@ -0,0 +1,116 @@
/*
* ll_dmadrivenusartcore.cpp
*
* Created on: Nov 4, 2019
* Author: abody
*/
#include <ll_usartcore.h>
namespace f4ll {
LL_UsartCore::LL_UsartCore(USART_TypeDef *usart, DMA_TypeDef *dma, uint32_t streamRx, uint32_t streamTx)
: m_usart(usart)
, m_rxDma(dma, streamRx)
, m_txDma(dma, streamTx)
{
LL_DMA_EnableIT_TC(dma, streamRx);
LL_DMA_EnableIT_TE(dma, streamRx);
LL_DMA_EnableIT_TC(dma, streamTx);
LL_DMA_EnableIT_TE(dma, streamTx);
LL_USART_EnableIT_IDLE(usart);
}
void LL_UsartCore::UsartIsr()
{
if(LL_USART_IsActiveFlag_IDLE(m_usart) && LL_USART_IsEnabledIT_IDLE(m_usart)) { // receiver idle
LL_USART_ClearFlag_IDLE(m_usart);
ReceiverIdle();
} else if(LL_USART_IsActiveFlag_TC(m_usart) && LL_USART_IsEnabledIT_TC(m_usart)) { // transmission complete
LL_USART_DisableIT_TC(m_usart);
TransmissionComplete();
}
}
void LL_UsartCore::RxDmaIsr()
{
if(*m_rxDma.GetIsReg() & m_rxDma.GetTcMask()) {
*m_rxDma.GetIfcReg() = m_rxDma.GetTcMask();
if(m_rxDma.IsEnabledIt_TC())
RxDmaTransferComplete();
}
if(*m_rxDma.GetIsReg() & m_rxDma.GetHtMask()) {
*m_rxDma.GetIfcReg() = m_rxDma.GetHtMask();
if(m_rxDma.IsEnabledIt_HT())
RxDmaHalfTransfer();
}
if(*m_rxDma.GetIsReg() & m_rxDma.GetTeMask()) {
*m_rxDma.GetIfcReg() = m_rxDma.GetTeMask();
if(m_rxDma.IsEnabledIt_TE())
RxDmaError(LL_DmaHelper::DmaErrorType::Transfer);
}
if(*m_rxDma.GetIsReg() & m_rxDma.GetFeMask()) {
*m_rxDma.GetIfcReg() = m_rxDma.GetFeMask();
if(m_rxDma.IsEnabledIt_FE())
RxDmaError(LL_DmaHelper::DmaErrorType::Fifo);
}
if(*m_rxDma.GetIsReg() & m_rxDma.GetDmeMask()) {
*m_rxDma.GetIfcReg() = m_rxDma.GetDmeMask();
if(m_rxDma.IsEnabledIt_DME())
RxDmaError(LL_DmaHelper::DmaErrorType::DirectMode);
}
}
void LL_UsartCore::TxDmaIsr()
{
if(*m_txDma.GetIsReg() & m_txDma.GetTcMask()) { // DMA transfer complete
*m_txDma.GetIfcReg() = m_txDma.GetTcMask();
if(m_txDma.IsEnabledIt_TC())
TxDmaTransferComplete();
}
if(*m_txDma.GetIsReg() & m_txDma.GetHtMask()) {
*m_txDma.GetIfcReg() = m_txDma.GetHtMask();
if(m_txDma.IsEnabledIt_HT())
TxDmaHalfTransfer();
}
if(*m_txDma.GetIsReg() & m_txDma.GetTeMask()) {
*m_txDma.GetIfcReg() = m_txDma.GetTeMask();
if(m_txDma.IsEnabledIt_TE())
TxDmaError(LL_DmaHelper::DmaErrorType::Transfer);
}
if(*m_txDma.GetIsReg() & m_txDma.GetFeMask()) {
*m_txDma.GetIfcReg() = m_txDma.GetFeMask();
if(m_txDma.IsEnabledIt_FE())
TxDmaError(LL_DmaHelper::DmaErrorType::Fifo);
}
if(*m_txDma.GetIsReg() & m_txDma.GetDmeMask()) {
*m_txDma.GetIfcReg() = m_txDma.GetDmeMask();
if(m_txDma.IsEnabledIt_DME())
TxDmaError(LL_DmaHelper::DmaErrorType::DirectMode);
}
}
void LL_UsartCore::SetupTransmit(void const *buffer, uint16_t length)
{
LL_DMA_ConfigAddresses(m_txDma.GetDma(), m_txDma.GetStream(), reinterpret_cast<uint32_t>(buffer),
LL_USART_DMA_GetRegAddr(m_usart), LL_DMA_DIRECTION_MEMORY_TO_PERIPH);
LL_DMA_SetDataLength(m_txDma.GetDma(), m_txDma.GetStream(), length);
LL_USART_EnableDMAReq_TX(m_usart);
LL_DMA_EnableStream(m_txDma.GetDma(), m_txDma.GetStream());
}
void LL_UsartCore::SetupReceive(void *buffer, uint16_t length)
{
LL_DMA_ConfigAddresses(m_rxDma.GetDma(), m_rxDma.GetStream(), LL_USART_DMA_GetRegAddr(m_usart),
reinterpret_cast<uint32_t>(buffer), LL_DMA_DIRECTION_PERIPH_TO_MEMORY);
LL_DMA_SetDataLength(m_rxDma.GetDma(), m_rxDma.GetStream(), length);
LL_USART_EnableDMAReq_RX(m_usart);
LL_USART_ClearFlag_ORE(m_usart);
LL_DMA_EnableStream(m_rxDma.GetDma(), m_rxDma.GetStream());
}
} /* namespace f4ll */

51
lib/ll_usartcore.h Normal file
View file

@ -0,0 +1,51 @@
/*
* ll_dmadrivenusartcore.h
*
* Created on: Nov 4, 2019
* Author: abody
*/
#ifndef LL_USARTCORE_H_
#define LL_USARTCORE_H_
#include <platform/usart_ll.h>
#include "ll_dmahelper.h"
namespace f4ll {
class LL_UsartCore
{
public:
static inline void HandleUsartIrq(LL_UsartCore *_this) { _this->UsartIsr(); }
static inline void HandleRxDmaIrq(LL_UsartCore *_this) { _this->RxDmaIsr(); }
static inline void HandleTxDmaIrq(LL_UsartCore *_this) { _this->TxDmaIsr(); }
protected:
LL_UsartCore(USART_TypeDef *usart, DMA_TypeDef *dma, uint32_t streamRx, uint32_t streamTx);
virtual void ReceiverIdle() = 0;
virtual void TransmissionComplete() = 0;
virtual void RxDmaTransferComplete() = 0;
virtual void RxDmaHalfTransfer() = 0;
virtual void RxDmaError(LL_DmaHelper::DmaErrorType reason) = 0;
virtual void TxDmaTransferComplete() = 0;
virtual void TxDmaHalfTransfer() = 0;
virtual void TxDmaError(LL_DmaHelper::DmaErrorType reason) = 0;
void SetupTransmit(void const *buffer, uint16_t length);
void SetupReceive(void *buffer, uint16_t length);
void UsartIsr();
void RxDmaIsr();
void TxDmaIsr();
USART_TypeDef *m_usart;
LL_DmaHelper m_rxDma;
LL_DmaHelper m_txDma;
};
} /* namespace f4ll */
#endif /* LL_USARTCORE_H_ */