git subrepo clone ssh://git@codeberg.org/abody/f4ll.git components/f4ll

subrepo:
  subdir:   "components/f4ll"
  merged:   "a4df325"
upstream:
  origin:   "ssh://git@codeberg.org/abody/f4ll.git"
  branch:   "master"
  commit:   "a4df325"
git-subrepo:
  version:  "0.4.9"
  origin:   "???"
  commit:   "???"
This commit is contained in:
Attila Body 2025-06-09 18:13:21 +02:00
parent ce3dd83b9f
commit 61fce5992e
Signed by: abody
GPG key ID: BD0C6214E68FB5CF
22 changed files with 1750 additions and 0 deletions

View file

@ -0,0 +1,100 @@
/*
* ll_consolehandler.cpp
*
* Created on: Nov 7, 2019
* Author: abody
*/
#include <f4ll/console_handler.h>
#include <f4ll/irq_lock.h>
#include <f4ll/str_util.h>
#include <cstring>
namespace f4ll {
console_handler::console_handler(USART_TypeDef *usart, DMA_TypeDef *dma, uint32_t stream_rx, uint32_t stream_tx)
: usart_core(usart, dma, stream_rx, stream_tx)
{
}
void console_handler::receiver_idle(void) {}
void console_handler::transmission_complete(void)
{
m_tx_buffer.consumed(m_in_flight_size);
if (m_tx_buffer.commited()) {
uint8_t const *chunk;
m_tx_buffer.get_chunk(m_tx_buffer.size(), chunk, m_in_flight_size);
if (m_in_flight_size) {
setup_transmit(chunk, m_in_flight_size);
}
} else {
m_in_flight_size = 0;
}
}
void console_handler::framing_error(void) {}
void console_handler::overrun(void) {}
void console_handler::rx_dma_transfer_complete(void) {}
void console_handler::rx_dma_half_transfer(void) {}
void console_handler::rx_dma_error(dma_helper::dma_error_type reason)
{
(void)reason;
}
void console_handler::tx_dma_transfer_complete(void)
{
LL_USART_EnableIT_TC(m_usart);
LL_DMA_DisableStream(m_tx_dma.get_dma(), m_tx_dma.get_stream());
}
void console_handler::tx_dma_half_transfer(void) {}
void console_handler::tx_dma_error(dma_helper::dma_error_type reason)
{
(void)reason;
}
size_t console_handler::append(char const *s)
{
size_t len = strlen(s);
if (!len) {
return 0;
}
return len - m_tx_buffer.put(reinterpret_cast<uint8_t const *>(s), len);
}
void console_handler::flush()
{
bool busy;
if (!m_tx_buffer.uncommited()) {
return;
}
m_tx_buffer.commit();
{
irq_lock l;
busy = m_in_flight_size != 0;
}
if (busy) {
return;
}
uint8_t const *chunk;
m_tx_buffer.get_chunk(m_tx_buffer.size(), chunk, m_in_flight_size);
if (m_in_flight_size) {
setup_transmit(chunk, m_in_flight_size);
}
}
void console_handler::print(char const *s)
{
append(s);
flush();
}
} /* namespace f4ll */

View file

@ -0,0 +1,160 @@
/*
* ll_crc_handler.cpp
*
* Created on: Oct 26, 2019
* Author: compi
*/
#include <f4ll/crc_handler.h>
namespace f4ll {
crc_handler::crc_handler(DMA_TypeDef *dma, uint32_t stream)
: m_dma(dma, stream)
{
LL_DMA_EnableIT_TC(dma, stream);
LL_DMA_EnableIT_TE(dma, stream);
LL_DMA_SetM2MDstAddress(dma, stream, (uint32_t)&CRC->DR);
}
void crc_handler::attach_slot(slot_base &slot)
{
for (unsigned int i = 0; i < slot.m_task_count; ++i) {
auto &task(slot[i]);
task.m_address = nullptr;
task.m_word_count = 0;
task.m_callback = nullptr;
task.m_callback_param = 0;
}
uint32_t prim = __get_PRIMASK();
__disable_irq();
slot.m_next = m_first_slot;
m_first_slot = &slot;
__set_PRIMASK(prim);
}
bool crc_handler::enqueue(slot_base &slot, uint8_t task, void const *address, uint16_t len, icallback *cb, uintptr_t cb_param)
{
uint32_t prim = __get_PRIMASK();
bool immediate;
// TODO: do we need sanity check here? (is slot attached, is task in range,
// etc...?)
while (is_active(slot, task))
;
__disable_irq();
immediate = m_active_slot == nullptr;
slot[task].m_address = (!immediate) ? address : nullptr;
slot[task].m_word_count = (len + 3) / 4;
slot[task].m_callback = cb;
slot[task].m_callback_param = cb_param;
if (immediate) {
m_active_slot = &slot;
m_active_task = task;
}
__set_PRIMASK(prim);
if (immediate) {
CRC->CR = 1;
LL_DMA_SetM2MSrcAddress(m_dma.get_dma(), m_dma.get_stream(), (uint32_t)address);
LL_DMA_SetDataLength(m_dma.get_dma(), m_dma.get_stream(), (len + 3) / 4);
LL_DMA_EnableStream(m_dma.get_dma(), m_dma.get_stream());
}
return immediate;
}
bool crc_handler::is_active(slot_base &slot, uint8_t task) const
{
return task < slot.m_task_count && slot[task].m_word_count != 0;
}
bool crc_handler::is_queued(slot_base &slot, uint8_t task) const
{
return task < slot.m_task_count && slot[task].m_address != nullptr;
}
bool crc_handler::is_running(slot_base &slot, uint8_t task) const
{
return task < slot.m_task_count && slot[task].m_word_count && !slot[task].m_address;
}
void crc_handler::dma_transfer_completed(void)
{
if (*m_dma.get_is_reg() & m_dma.get_tc_mask()) { // DMA transfer complete
*m_dma.get_ifc_reg() = m_dma.get_tc_mask();
LL_DMA_DisableStream(m_dma.get_dma(), m_dma.get_stream());
if (m_active_slot) {
if ((*m_active_slot)[m_active_task].m_callback) {
(*m_active_slot)[m_active_task].m_callback->crc_succeeded(
(*m_active_slot)[m_active_task].m_callback_param, CRC->DR, m_active_task);
} else if ((*m_active_slot)[m_active_task].m_callback_param) {
*reinterpret_cast<uint32_t *>((*m_active_slot)[m_active_task].m_callback_param) = CRC->DR;
}
}
} else if (*m_dma.get_is_reg() & m_dma.get_te_mask()) { // DMA transfer error
*m_dma.get_ifc_reg() = m_dma.get_te_mask();
LL_DMA_DisableStream(m_dma.get_dma(), m_dma.get_stream());
if (m_active_slot) {
if ((*m_active_slot)[m_active_task].m_callback) {
(*m_active_slot)[m_active_task].m_callback->crc_failed(
(*m_active_slot)[m_active_task].m_callback_param, CRC->DR, m_active_task);
} else if ((*m_active_slot)[m_active_task].m_callback_param) {
*reinterpret_cast<uint32_t *>((*m_active_slot)[m_active_task].m_callback_param) = -1;
}
}
}
(*m_active_slot)[m_active_task].m_callback = nullptr;
(*m_active_slot)[m_active_task].m_callback_param = 0;
(*m_active_slot)[m_active_task].m_word_count = 0;
start_next_task();
}
void crc_handler::start_next_task(void)
{
bool more_tasks;
uint8_t index = 0;
do {
slot_base volatile *slot = m_first_slot;
more_tasks = false;
while (slot) {
if (index < slot->m_task_count) {
if ((*slot)[index].m_address) {
m_active_slot = slot;
m_active_task = index;
CRC->CR = 1;
LL_DMA_SetM2MSrcAddress(m_dma.get_dma(), m_dma.get_stream(), reinterpret_cast<uint32_t>((*slot)[index].m_address));
LL_DMA_SetDataLength(m_dma.get_dma(), m_dma.get_stream(), (*slot)[index].m_word_count);
LL_DMA_EnableStream(m_dma.get_dma(), m_dma.get_stream());
(*slot)[index].m_address = nullptr; // marking as started
return;
}
if (index + 1 < slot->m_task_count) {
more_tasks = true;
}
}
slot = slot->m_next;
}
++index;
} while (more_tasks);
m_active_slot = nullptr;
}
void crc_handler::wait_results(slot_base &slot, uint8_t task) const
{
while (is_queued(slot, task))
;
while (is_active(slot, task))
;
}
uint32_t crc_handler::compute(slot_base &slot, uint8_t task, void const *address, uint16_t len)
{
uint32_t result;
enqueue(slot, task, address, len, nullptr, reinterpret_cast<uintptr_t>(&result));
while (is_active(slot, task))
;
return result;
}
} // namespace f4ll

View file

@ -0,0 +1,24 @@
/*
q * ll_dmahelper.cpp
*
* Created on: Oct 25, 2019
* Author: abody
*/
#include <f4ll/dma_helper.h>
namespace f4ll {
dma_helper::dma_helper(DMA_TypeDef *dma, uint32_t stream)
: m_dma(dma),
m_stream(stream),
m_is_reg(
(dma == DMA1) ? ((m_stream < LL_DMA_STREAM_4) ? &DMA1->LISR : &DMA1->HISR)
: ((m_stream < LL_DMA_STREAM_4) ? &DMA2->LISR : &DMA2->HISR)),
m_ifc_reg(
(dma == DMA1) ? ((m_stream < LL_DMA_STREAM_4) ? &DMA1->LIFCR : &DMA1->HIFCR)
: ((m_stream < LL_DMA_STREAM_4) ? &DMA2->LIFCR : &DMA2->HIFCR))
{
}
} /* namespace f4ll */

View file

@ -0,0 +1,150 @@
/*
* fault.c
*
* Created on: Oct 1, 2019
* Author: abody
* -c "tpiu config internal <logfile_full_path> uart off <cpufreq>"
*/
#include <inttypes.h>
//#include <core_cm4.h>
#include <f4ll/fault.h>
#include <f4ll/str_util.h>
#include <stm32f4xx.h>
#ifdef __cplusplus
extern "C" {
#endif
fault_context_t g_fault_context;
void __attribute__((weak)) app_fault_callback(uint32_t reason)
{
(void)reason;
}
void swo_send_str(char const *str, uint8_t len, uint8_t port)
{
while(len) {
if (((ITM->TCR & ITM_TCR_ITMENA_Msk) != 0UL) && // ITM enabled
((ITM->TER & (1UL << port) ) != 0UL) ) // ITM Port enabled
{
// Wait until shift register is free
while (ITM->PORT[port].u32 == 0UL) {
__ASM volatile ("nop");
}
if(len >= 4) {
ITM->PORT[port].u32 = *(uint32_t*)(str);
str += 4;
len -= 4;
} else if(len >= 2) {
ITM->PORT[port].u16 = *(uint16_t*)(str);
str += 2;
len -= 2;
} else {
ITM->PORT[port].u8 = *(uint8_t*)(str);
++str;
--len;
}
} else
break;
}
}
void fault_print_str(char const *fmtstr, uint32_t *values)
{
char hex_str[9]={0};
char const *next_chunk = fmtstr;
while(*fmtstr) {
if(*fmtstr == '%') {
swo_send_str(next_chunk, fmtstr - next_chunk, 0);
uitohex(hex_str, *values++, 8);
swo_send_str(hex_str, 8, 0);
next_chunk = fmtstr + 1;
}
++fmtstr;
}
if (next_chunk != fmtstr) {
swo_send_str(next_chunk, fmtstr - next_chunk, 0);
}
}
void fault_handler(uint32_t type, fault_context_t *context)
{
uint32_t FSR[9] = {
SCB->HFSR,
0xff & SCB->CFSR,
(0xff00 & SCB->CFSR) >> 8,
(0xffff0000 & SCB->CFSR) >> 16,
SCB->DFSR,
SCB->AFSR,
SCB->SHCSR,
SCB->MMFAR,
SCB->BFAR
};
while(1) {
fault_print_str("\n++ Fault Handler ++\n\nFaultType: ",NULL);
switch( type ) {
case FAULT_REASON_HARD_FAULT:
fault_print_str("HardFault",NULL);
break;
case FAULT_REASON_MEMMANAGE_FAULT:
fault_print_str("MemManageFault",NULL);
break;
case FAULT_REASON_BUS_FAULT:
fault_print_str("BusFault",NULL);
break;
case FAULT_REASON_USAGE_FAULT:
fault_print_str("UsageFault",NULL);
break;
default:
fault_print_str("Unknown Fault",NULL);
break;
}
fault_print_str("\n\nContext:",NULL);
fault_print_str(
"\nR0 : %"
"\nR1 : %"
"\nR2 : %"
"\nR3 : %"
"\nR4 : %"
"\nR5 : %"
"\nR6 : %"
"\nR7 : %"
"\nR8 : %"
"\nR9 : %"
"\nR10 : %"
"\nR11 : %"
"\nR12 : %"
"\nSP : %"
"\nLR : %"
"\nPC : %"
"\nxPSR : %"
"\nPSP : %"
"\nMSP : %",
(uint32_t *)context);
//Capture CPUID to get core/cpu info
fault_print_str("\nCPUID: %",(uint32_t *)&SCB->CPUID);
fault_print_str(
"\nHFSR : %"
"\nMMFSR: %"
"\nBFSR : %"
"\nUFSR : %"
"\nDFSR : %"
"\nAFSR : %"
"\nSHCSR: %",
FSR);
app_fault_callback(type);
}
}
#ifdef __cplusplus
}
#endif

View file

@ -0,0 +1,38 @@
/*
* llmemcpydma.cpp
*
* Created on: Nov 4, 2019
* Author: abody
*/
#include <f4ll/memcpy_dma.h>
namespace f4ll {
memcpy_dma::memcpy_dma(DMA_TypeDef *dma, uint32_t stream)
: dma_helper(dma, stream)
{
LL_DMA_EnableIT_TC(dma, stream);
}
void *memcpy_dma::copy(void *dst, void const *src, uint16_t length)
{
LL_DMA_SetM2MSrcAddress(get_dma(), get_stream(), (uint32_t)src);
LL_DMA_SetM2MDstAddress(get_dma(), get_stream(), (uint32_t)dst);
LL_DMA_SetDataLength(get_dma(), get_stream(), (length + 3) / 4);
m_busy = 1;
LL_DMA_EnableStream(get_dma(), get_stream());
while (m_busy)
;
return dst;
}
void memcpy_dma::dma_transfer_completed()
{
if (*get_is_reg() & get_tc_mask()) { // DMA transfer complete
*get_ifc_reg() = get_tc_mask();
LL_DMA_DisableStream(get_dma(), get_stream());
m_busy = 0;
}
}
} /* namespace f4ll */

View file

@ -0,0 +1,212 @@
/*
* ll_hsusart_impl.h
*
* Created on: Oct 29, 2019
* Author: abody
*/
#include <f4ll/packet_usart.h>
#include <string.h>
namespace f4ll {
template <typename T> static inline T round_up_to_4(T input)
{
return (input + 3) & (((T)-1) - 3);
}
packet_usart::packet_usart(USART_TypeDef *usart, DMA_TypeDef *dma, uint32_t stream_rx, uint32_t stream_tx)
: usart_core(usart, dma, stream_rx, stream_tx)
{
crc_handler::instance().attach_slot(m_crc_slot);
LL_USART_EnableIT_IDLE(usart);
LL_USART_EnableIT_ERROR(usart);
}
void packet_usart::rx_processed(bool second)
{
m_rx_buffers[second].busy = false;
m_rx_buffers[second].error = false;
}
void packet_usart::set_callback(ihs_usart_callback *callback, uintptr_t callback_param)
{
m_user_callback = callback;
m_user_callback_param = callback_param;
}
void packet_usart::post_packet(uint8_t const *payload, uint8_t length, bool wait_for_crc_queue)
{
uint16_t payload_length = round_up_to_4((uint16_t)length);
build_header(m_tx_buffer.pkt, m_tx_serial_nr++, length);
if (payload) {
memcpy(m_tx_buffer.pkt.payload, payload, length);
}
m_tx_buffer.requested_length = sizeof(m_tx_buffer.pkt.header) + payload_length + sizeof(uint32_t);
m_tx_buffer.busy = true;
m_tx_buffer.error = false;
crc_handler::instance().enqueue(
m_crc_slot, 0, &m_tx_buffer.pkt, sizeof(packet_header) + payload_length, nullptr,
reinterpret_cast<uintptr_t>(m_tx_buffer.pkt.payload + payload_length));
while (wait_for_crc_queue && crc_handler::instance().is_queued(m_crc_slot, 0))
;
setup_transmit(&m_tx_buffer.pkt, m_tx_buffer.requested_length);
++m_stats.sent;
}
void packet_usart::setup_receive()
{
m_rx_buffers[m_rx_buffer_selector].requested_length = sizeof(m_rx_buffers[m_rx_buffer_selector].pkt);
usart_core::setup_receive(&m_rx_buffers[m_rx_buffer_selector], sizeof(m_rx_buffers[m_rx_buffer_selector].pkt));
}
//////////////////////////////////////
// UsartCore pure virtual functions //
//////////////////////////////////////
void packet_usart::receiver_idle(void)
{
uint16_t rcvdLen =
m_rx_buffers[m_rx_buffer_selector].requested_length - LL_DMA_GetDataLength(m_rx_dma.get_dma(), m_rx_dma.get_stream());
if (rcvdLen >= sizeof(packet_header)) {
if (check_header(m_rx_buffers[m_rx_buffer_selector].pkt.header)) {
if (rcvdLen >= sizeof(packet_header) + round_up_to_4((uint16_t)m_rx_buffers[m_rx_buffer_selector].pkt.header.payload_length) +
sizeof(uint32_t)) {
LL_DMA_DisableStream(m_rx_dma.get_dma(), m_rx_dma.get_stream());
} else {
++m_stats.premature_payload;
}
} else {
m_rx_buffers[m_rx_buffer_selector].error = 1;
LL_DMA_DisableStream(m_rx_dma.get_dma(), m_rx_dma.get_stream());
}
} else {
++m_stats.premature_hdr;
}
}
void packet_usart::transmission_complete(void)
{
LL_USART_DisableDirectionTx(m_usart); // enforcing an idle frame
LL_USART_EnableDirectionTx(m_usart);
m_tx_buffer.busy = 0;
}
void packet_usart::framing_error(void) {}
void packet_usart::overrun(void) {}
void packet_usart::rx_dma_transfer_complete(void)
{
if (check_header(m_rx_buffers[m_rx_buffer_selector].pkt.header)) {
crc_handler::instance().enqueue(
m_crc_slot, 1, &m_rx_buffers[m_rx_buffer_selector].pkt,
sizeof(packet_header) + round_up_to_4((uint16_t)m_rx_buffers[m_rx_buffer_selector].pkt.header.payload_length), this,
m_rx_buffer_selector);
} else {
++m_stats.hdr_error;
m_rx_buffers[m_rx_buffer_selector].error = true;
}
switch_rx_buffers();
}
void packet_usart::rx_dma_half_transfer(void) {}
void packet_usart::rx_dma_error(dma_helper::dma_error_type reason)
{
(void)reason;
m_rx_buffers[m_rx_buffer_selector].error = 1;
++m_stats.rx_dma_error;
switch_rx_buffers();
}
void packet_usart::tx_dma_transfer_complete(void)
{
LL_USART_EnableIT_TC(m_usart);
LL_DMA_DisableStream(m_tx_dma.get_dma(), m_tx_dma.get_stream());
}
void packet_usart::tx_dma_half_transfer(void) {}
void packet_usart::tx_dma_error(dma_helper::dma_error_type reason)
{
(void)reason;
m_tx_buffer.error = 1;
++m_stats.tx_dma_error;
}
///////////////////////
// Private functions //
///////////////////////
void packet_usart::build_header(packet &packet, uint8_t serial_nr, uint8_t length)
{
uint8_t hash = STARTMARKER;
packet.header.start_byte = STARTMARKER;
packet.header.serial = serial_nr;
hash ^= serial_nr;
packet.header.payload_length = length;
hash ^= length;
packet.header.hash = hash;
}
bool packet_usart::check_header(packet_header &header)
{
return header.start_byte == STARTMARKER && (header.start_byte ^ header.serial ^ header.payload_length) == header.hash;
}
void packet_usart::switch_rx_buffers(void)
{
++m_stats.rcvd;
m_rx_buffer_selector = !m_rx_buffer_selector;
if (m_rx_buffers[m_rx_buffer_selector].busy) {
++m_stats.overrun;
}
setup_receive();
}
///////////////////////////
// crc_handler::ICallback //
///////////////////////////
void packet_usart::crc_succeeded(uintptr_t callback_param, uint32_t crc, uint8_t task)
{
(void)task;
Buffer &buf(m_rx_buffers[static_cast<int>(callback_param)]);
buf.busy = 1;
if (*(uint32_t *)(buf.pkt.payload + round_up_to_4((uint16_t)buf.pkt.header.payload_length)) != crc) {
buf.error = 1;
buf.error_info = crc;
++m_stats.payload_errror;
}
if (m_user_callback) {
buf.busy = !m_user_callback->packet_received(this, m_user_callback_param, buf.pkt);
}
}
void packet_usart::crc_failed(uintptr_t callback_param, uint32_t crc, uint8_t task)
{
(void)crc;
(void)task;
Buffer &buf(m_rx_buffers[static_cast<int>(callback_param)]);
buf.busy = buf.error = true;
buf.error_info = 0;
++m_stats.payload_errror;
if (m_user_callback) {
buf.busy = !m_user_callback->packet_received(this, m_user_callback_param, buf.pkt);
}
}
} // namespace f4ll

View file

@ -0,0 +1,105 @@
#include <f4ll/str_util.h>
#include <stdint.h>
//////////////////////////////////////////////////////////////////////////////
size_t strcpy_ex(char *dst, char const *src)
{
size_t ret = 0;
do {
*dst++ = *src;
++ret;
} while (*src++);
return ret - 1;
}
//////////////////////////////////////////////////////////////////////////////
void strrev(char *first, char *last)
{
char tmp;
while (last > first) {
tmp = *first;
*first++ = *last;
*last-- = tmp;
}
}
//////////////////////////////////////////////////////////////////////////////
char tochr(const uint8_t in, const uint8_t upper)
{
return in + ((in < 10) ? '0' : (upper ? 'A' : 'a') - 10);
}
//////////////////////////////////////////////////////////////////////////////
size_t uitodec(char *buffer, uint32_t data)
{
char *b2 = buffer;
if (!data) {
*b2++ = '0';
*b2 = '\0';
return 1;
}
while (data) {
*b2++ = (data % 10) + '0';
data /= 10;
}
size_t ret = b2 - buffer;
*b2-- = 0;
strrev(buffer, b2);
return ret;
}
//////////////////////////////////////////////////////////////////////////////
size_t uitohex(char *buffer, uint32_t data, uint8_t chars)
{
char *b2 = buffer;
size_t ret = 0;
if (chars == 0xff || !chars) {
if (!data) {
*b2++ = '0';
*b2 = '\0';
return 1;
}
while (data) {
uint8_t curval = data & 0x0f;
*b2++ = tochr(curval, 1);
data >>= 4;
}
ret = b2 - buffer;
} else {
ret = chars;
for (uint8_t pos = 0; pos < (uint8_t)ret; ++pos) {
*b2++ = tochr(data & 0x0f, 1);
data >>= 4;
}
}
*b2-- = 0;
strrev(buffer, b2);
return ret;
}
//////////////////////////////////////////////////////////////////////////////
size_t itodec(char *buffer, int data)
{
if (data < 0) {
*buffer++ = '-';
return uitodec(buffer, -data) + 1;
}
return uitodec(buffer, data);
}
//////////////////////////////////////////////////////////////////////////////
size_t itohex(char *buffer, int data)
{
if (data < 0) {
*buffer++ = '-';
return uitohex(buffer, -data, 0) + 1;
}
return uitohex(buffer, data, 0);
}

View file

@ -0,0 +1,145 @@
/*
* ll_dmadrivenusartcore.cpp
*
* Created on: Nov 4, 2019
* Author: abody
*/
#include <f4ll/usart_core.h>
namespace f4ll {
usart_core::usart_core(USART_TypeDef *usart, DMA_TypeDef *dma, uint32_t streamRx, uint32_t streamTx)
: m_usart(usart),
m_rx_dma(dma, streamRx),
m_tx_dma(dma, streamTx)
{
uint32_t status = usart->SR;
volatile uint32_t tmpreg = usart->DR; // clearing some of the error/status bits in the USART
(void)tmpreg;
(void)status;
*m_tx_dma.get_ifc_reg() =
m_tx_dma.get_tc_mask() | m_rx_dma.get_ht_mask() | m_tx_dma.get_te_mask() | m_rx_dma.get_fe_mask() | m_rx_dma.get_dme_mask();
*m_rx_dma.get_ifc_reg() =
m_rx_dma.get_tc_mask() | m_rx_dma.get_ht_mask() | m_rx_dma.get_te_mask() | m_rx_dma.get_fe_mask() | m_rx_dma.get_dme_mask();
LL_DMA_EnableIT_TC(dma, streamRx);
LL_DMA_EnableIT_TE(dma, streamRx);
LL_DMA_EnableIT_TC(dma, streamTx);
LL_DMA_EnableIT_TE(dma, streamTx);
}
void usart_core::usart_isr()
{
uint32_t status = m_usart->SR;
volatile uint32_t tmpreg = m_usart->DR; // clearing some of the error/status bits in the HW
(void)tmpreg;
if (LL_USART_IsEnabledIT_TC(m_usart) && LL_USART_IsActiveFlag_TC(m_usart)) { // transmission complete
LL_USART_DisableIT_TC(m_usart);
transmission_complete();
}
if (LL_USART_IsEnabledIT_IDLE(m_usart) && (status & USART_SR_IDLE)) {
receiver_idle();
}
if (LL_USART_IsEnabledIT_ERROR(m_usart)) {
if (status & USART_SR_FE) {
framing_error();
}
if (status & USART_SR_ORE) {
overrun();
}
}
}
void usart_core::rx_dma_isr()
{
if (*m_rx_dma.get_is_reg() & m_rx_dma.get_tc_mask()) {
*m_rx_dma.get_ifc_reg() = m_rx_dma.get_tc_mask();
if (m_rx_dma.is_enabled_it_tc()) {
rx_dma_transfer_complete();
}
}
if (*m_rx_dma.get_is_reg() & m_rx_dma.get_ht_mask()) {
*m_rx_dma.get_ifc_reg() = m_rx_dma.get_ht_mask();
if (m_rx_dma.is_enabled_it_ht()) {
rx_dma_half_transfer();
}
}
if (*m_rx_dma.get_is_reg() & m_rx_dma.get_te_mask()) {
*m_rx_dma.get_ifc_reg() = m_rx_dma.get_te_mask();
if (m_rx_dma.is_enabled_it_te()) {
rx_dma_error(dma_helper::dma_error_type::transfer);
}
}
if (*m_rx_dma.get_is_reg() & m_rx_dma.get_fe_mask()) {
*m_rx_dma.get_ifc_reg() = m_rx_dma.get_fe_mask();
if (m_rx_dma.is_enabled_it_fe()) {
rx_dma_error(dma_helper::dma_error_type::fifo);
}
}
if (*m_rx_dma.get_is_reg() & m_rx_dma.get_dme_mask()) {
*m_rx_dma.get_ifc_reg() = m_rx_dma.get_dme_mask();
if (m_rx_dma.is_enabled_it_dme()) {
rx_dma_error(dma_helper::dma_error_type::direct_mode);
}
}
}
void usart_core::tx_dma_isr()
{
if (*m_tx_dma.get_is_reg() & m_tx_dma.get_tc_mask()) { // DMA transfer complete
*m_tx_dma.get_ifc_reg() = m_tx_dma.get_tc_mask();
if (m_tx_dma.is_enabled_it_tc()) {
tx_dma_transfer_complete();
}
}
if (*m_tx_dma.get_is_reg() & m_tx_dma.get_ht_mask()) {
*m_tx_dma.get_ifc_reg() = m_tx_dma.get_ht_mask();
if (m_tx_dma.is_enabled_it_ht()) {
tx_dma_half_transfer();
}
}
if (*m_tx_dma.get_is_reg() & m_tx_dma.get_te_mask()) {
*m_tx_dma.get_ifc_reg() = m_tx_dma.get_te_mask();
if (m_tx_dma.is_enabled_it_te()) {
tx_dma_error(dma_helper::dma_error_type::transfer);
}
}
if (*m_tx_dma.get_is_reg() & m_tx_dma.get_fe_mask()) {
*m_tx_dma.get_ifc_reg() = m_tx_dma.get_fe_mask();
if (m_tx_dma.is_enabled_it_fe()) {
tx_dma_error(dma_helper::dma_error_type::fifo);
}
}
if (*m_tx_dma.get_is_reg() & m_tx_dma.get_dme_mask()) {
*m_tx_dma.get_ifc_reg() = m_tx_dma.get_dme_mask();
if (m_tx_dma.is_enabled_it_dme()) {
tx_dma_error(dma_helper::dma_error_type::direct_mode);
}
}
}
void usart_core::setup_transmit(void const *buffer, uint16_t length)
{
LL_DMA_ConfigAddresses(
m_tx_dma.get_dma(), m_tx_dma.get_stream(), reinterpret_cast<uint32_t>(buffer), LL_USART_DMA_GetRegAddr(m_usart),
LL_DMA_DIRECTION_MEMORY_TO_PERIPH);
LL_DMA_SetDataLength(m_tx_dma.get_dma(), m_tx_dma.get_stream(), length);
LL_USART_EnableDMAReq_TX(m_usart);
LL_DMA_EnableStream(m_tx_dma.get_dma(), m_tx_dma.get_stream());
}
void usart_core::setup_receive(void *buffer, uint16_t length)
{
LL_DMA_ConfigAddresses(
m_rx_dma.get_dma(), m_rx_dma.get_stream(), LL_USART_DMA_GetRegAddr(m_usart), reinterpret_cast<uint32_t>(buffer),
LL_DMA_DIRECTION_PERIPH_TO_MEMORY);
LL_DMA_SetDataLength(m_rx_dma.get_dma(), m_rx_dma.get_stream(), length);
LL_USART_EnableDMAReq_RX(m_usart);
LL_USART_ClearFlag_ORE(m_usart);
LL_DMA_EnableStream(m_rx_dma.get_dma(), m_rx_dma.get_stream());
}
} /* namespace f4ll */