mirror of
https://github.com/thelsing/knx.git
synced 2025-01-02 00:06:43 +01:00
Adds dma support for rp2040 uart
This commit is contained in:
parent
f5724c64d1
commit
6b2ac7e50b
@ -33,9 +33,66 @@ For usage of KNX-IP you have to define either
|
|||||||
|
|
||||||
// Pi Pico specific libs
|
// Pi Pico specific libs
|
||||||
#include <EEPROM.h> // EEPROM emulation in flash, part of Earl E Philhowers Pi Pico Arduino support
|
#include <EEPROM.h> // EEPROM emulation in flash, part of Earl E Philhowers Pi Pico Arduino support
|
||||||
#include <pico/unique_id.h> // from Pico SDK
|
|
||||||
#include <hardware/watchdog.h> // from Pico SDK
|
|
||||||
#include <hardware/flash.h> // from Pico SDK
|
#include <hardware/flash.h> // from Pico SDK
|
||||||
|
#include <hardware/watchdog.h> // from Pico SDK
|
||||||
|
#include <pico/unique_id.h> // from Pico SDK
|
||||||
|
|
||||||
|
#ifdef USE_KNX_DMA_UART
|
||||||
|
#include <hardware/dma.h>
|
||||||
|
// constexpr uint32_t uartDmaTransferCount = 0b1111111111;
|
||||||
|
constexpr uint32_t uartDmaTransferCount = UINT32_MAX;
|
||||||
|
constexpr uint8_t uartDmaBufferExp = 8u; // 2**BufferExp
|
||||||
|
constexpr uint16_t uartDmaBufferSize = (1u << uartDmaBufferExp);
|
||||||
|
int8_t uartDmaChannel = -1;
|
||||||
|
volatile uint8_t __attribute__((aligned(uartDmaBufferSize))) uartDmaBuffer[uartDmaBufferSize] = {};
|
||||||
|
volatile uint32_t uartDmaReadCount = 0;
|
||||||
|
volatile uint16_t uartDmaRestartCount = 0;
|
||||||
|
volatile uint32_t uartDmaWriteCount2 = 0;
|
||||||
|
volatile uint32_t uartDmaAvail = 0;
|
||||||
|
|
||||||
|
// Liefert die Zahl der gelesenen Bytes seit dem DMA Transferstart
|
||||||
|
inline uint32_t uartDmaWriteCount()
|
||||||
|
{
|
||||||
|
uartDmaWriteCount2 = uartDmaTransferCount - dma_channel_hw_addr(uartDmaChannel)->transfer_count;
|
||||||
|
return uartDmaWriteCount2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Liefert die aktuelle Schreibposition im DMA Buffer
|
||||||
|
inline uint16_t uartDmaWriteBufferPosition()
|
||||||
|
{
|
||||||
|
return uartDmaWriteCount() % uartDmaBufferSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Liefert die aktuelle Leseposition im DMA Buffer
|
||||||
|
inline uint16_t uartDmaReadBufferPosition()
|
||||||
|
{
|
||||||
|
return uartDmaReadCount % uartDmaBufferSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Liefert die aktuelle Leseposition als Pointer
|
||||||
|
inline uint8_t* uartDmaReadAddr()
|
||||||
|
{
|
||||||
|
return ((uint8_t*)uartDmaBuffer + uartDmaReadBufferPosition());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Startet den Transfer nach Abschluss neu.
|
||||||
|
void __time_critical_func(uartDmaRestart)()
|
||||||
|
{
|
||||||
|
// println("Restart");
|
||||||
|
uartDmaRestartCount = uartDmaWriteBufferPosition() - uartDmaReadBufferPosition();
|
||||||
|
|
||||||
|
// wenn uartDmaRestartCount == 0 ist, wurde alles verarbeitet und der read count kann mit dem neustart wieder auf 0 gesetzt werden.
|
||||||
|
if (uartDmaRestartCount == 0)
|
||||||
|
{
|
||||||
|
uartDmaReadCount = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
asm volatile("" ::: "memory");
|
||||||
|
dma_hw->ints0 = 1u << uartDmaChannel; // clear DMA IRQ0 flag
|
||||||
|
asm volatile("" ::: "memory");
|
||||||
|
dma_channel_set_write_addr(uartDmaChannel, uartDmaBuffer, true);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#define FLASHPTR ((uint8_t*)XIP_BASE + KNX_FLASH_OFFSET)
|
#define FLASHPTR ((uint8_t*)XIP_BASE + KNX_FLASH_OFFSET)
|
||||||
|
|
||||||
@ -57,7 +114,7 @@ extern Wiznet5500lwIP KNX_NETIF;
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
RP2040ArduinoPlatform::RP2040ArduinoPlatform()
|
RP2040ArduinoPlatform::RP2040ArduinoPlatform()
|
||||||
#ifndef KNX_NO_DEFAULT_UART
|
#if !defined(KNX_NO_DEFAULT_UART) && !defined(USE_KNX_DMA_UART)
|
||||||
: ArduinoPlatform(&KNX_SERIAL)
|
: ArduinoPlatform(&KNX_SERIAL)
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
@ -72,7 +129,8 @@ RP2040ArduinoPlatform::RP2040ArduinoPlatform()
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
RP2040ArduinoPlatform::RP2040ArduinoPlatform( HardwareSerial* s) : ArduinoPlatform(s)
|
RP2040ArduinoPlatform::RP2040ArduinoPlatform(HardwareSerial* s)
|
||||||
|
: ArduinoPlatform(s)
|
||||||
{
|
{
|
||||||
#ifndef USE_RP2040_EEPROM_EMULATION
|
#ifndef USE_RP2040_EEPROM_EMULATION
|
||||||
_memoryType = Flash;
|
_memoryType = Flash;
|
||||||
@ -85,13 +143,68 @@ void RP2040ArduinoPlatform::knxUartPins(pin_size_t rxPin, pin_size_t txPin)
|
|||||||
_txPin = txPin;
|
_txPin = txPin;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RP2040ArduinoPlatform::overflowUart() {
|
bool RP2040ArduinoPlatform::overflowUart()
|
||||||
|
{
|
||||||
|
#ifdef USE_KNX_DMA_UART
|
||||||
|
// during dma restart
|
||||||
|
bool ret;
|
||||||
|
const uint32_t writeCount = uartDmaWriteCount();
|
||||||
|
if (uartDmaRestartCount > 0)
|
||||||
|
ret = writeCount >= (uartDmaBufferSize - uartDmaRestartCount - 1);
|
||||||
|
else
|
||||||
|
ret = (writeCount - uartDmaReadCount) > uartDmaBufferSize;
|
||||||
|
|
||||||
|
// if (ret)
|
||||||
|
// {
|
||||||
|
// println(uartDmaWriteBufferPosition());
|
||||||
|
// println(uartDmaReadBufferPosition());
|
||||||
|
// println(uartDmaWriteCount());
|
||||||
|
// println(uartDmaReadCount);
|
||||||
|
// println(uartDmaRestartCount);
|
||||||
|
// printHex("BUF: ", (const uint8_t *)uartDmaBuffer, uartDmaBufferSize);
|
||||||
|
// println("OVERFLOW");
|
||||||
|
// while (true)
|
||||||
|
// ;
|
||||||
|
// }
|
||||||
|
return ret;
|
||||||
|
#else
|
||||||
SerialUART* serial = dynamic_cast<SerialUART*>(_knxSerial);
|
SerialUART* serial = dynamic_cast<SerialUART*>(_knxSerial);
|
||||||
return serial->overflow();
|
return serial->overflow();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void RP2040ArduinoPlatform::setupUart()
|
void RP2040ArduinoPlatform::setupUart()
|
||||||
{
|
{
|
||||||
|
#ifdef USE_KNX_DMA_UART
|
||||||
|
if (uartDmaChannel == -1)
|
||||||
|
{
|
||||||
|
// configure uart0
|
||||||
|
gpio_set_function(_rxPin, GPIO_FUNC_UART);
|
||||||
|
gpio_set_function(_txPin, GPIO_FUNC_UART);
|
||||||
|
uart_init(KNX_DMA_UART, 19200);
|
||||||
|
uart_set_hw_flow(KNX_DMA_UART, false, false);
|
||||||
|
uart_set_format(KNX_DMA_UART, 8, 1, UART_PARITY_EVEN);
|
||||||
|
uart_set_fifo_enabled(KNX_DMA_UART, false);
|
||||||
|
|
||||||
|
// configure uart0
|
||||||
|
uartDmaChannel = dma_claim_unused_channel(true); // get free channel for dma
|
||||||
|
dma_channel_config dmaConfig = dma_channel_get_default_config(uartDmaChannel);
|
||||||
|
channel_config_set_transfer_data_size(&dmaConfig, DMA_SIZE_8);
|
||||||
|
channel_config_set_read_increment(&dmaConfig, false);
|
||||||
|
channel_config_set_write_increment(&dmaConfig, true);
|
||||||
|
channel_config_set_high_priority(&dmaConfig, true);
|
||||||
|
channel_config_set_ring(&dmaConfig, true, uartDmaBufferExp);
|
||||||
|
channel_config_set_dreq(&dmaConfig, KNX_DMA_UART_DREQ);
|
||||||
|
dma_channel_set_read_addr(uartDmaChannel, &uart_get_hw(uart0)->dr, false);
|
||||||
|
dma_channel_set_write_addr(uartDmaChannel, uartDmaBuffer, false);
|
||||||
|
dma_channel_set_trans_count(uartDmaChannel, uartDmaTransferCount, false);
|
||||||
|
dma_channel_set_config(uartDmaChannel, &dmaConfig, true);
|
||||||
|
dma_channel_set_irq1_enabled(uartDmaChannel, true);
|
||||||
|
// irq_add_shared_handler(KNX_DMA_IRQ, uartDmaRestart, PICO_SHARED_IRQ_HANDLER_HIGHEST_ORDER_PRIORITY);
|
||||||
|
irq_set_exclusive_handler(KNX_DMA_IRQ, uartDmaRestart);
|
||||||
|
irq_set_enabled(KNX_DMA_IRQ, true);
|
||||||
|
}
|
||||||
|
#else
|
||||||
SerialUART* serial = dynamic_cast<SerialUART*>(_knxSerial);
|
SerialUART* serial = dynamic_cast<SerialUART*>(_knxSerial);
|
||||||
if (serial)
|
if (serial)
|
||||||
{
|
{
|
||||||
@ -100,13 +213,84 @@ void RP2040ArduinoPlatform::setupUart()
|
|||||||
if (_txPin != UART_PIN_NOT_DEFINED)
|
if (_txPin != UART_PIN_NOT_DEFINED)
|
||||||
serial->setTX(_txPin);
|
serial->setTX(_txPin);
|
||||||
serial->setPollingMode();
|
serial->setPollingMode();
|
||||||
|
serial->setFIFOSize(64);
|
||||||
}
|
}
|
||||||
|
|
||||||
_knxSerial->begin(19200, SERIAL_8E1);
|
_knxSerial->begin(19200, SERIAL_8E1);
|
||||||
while (!_knxSerial)
|
while (!_knxSerial)
|
||||||
;
|
;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef USE_KNX_DMA_UART
|
||||||
|
int RP2040ArduinoPlatform::uartAvailable()
|
||||||
|
{
|
||||||
|
if (uartDmaChannel == -1)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (uartDmaRestartCount > 0)
|
||||||
|
{
|
||||||
|
return uartDmaRestartCount;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
uint32_t tc = dma_channel_hw_addr(uartDmaChannel)->transfer_count;
|
||||||
|
uartDmaAvail = tc;
|
||||||
|
int test = uartDmaTransferCount - tc - uartDmaReadCount;
|
||||||
|
return test;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int RP2040ArduinoPlatform::readUart()
|
||||||
|
{
|
||||||
|
if (!uartAvailable())
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
int ret = uartDmaReadAddr()[0];
|
||||||
|
// print("< ");
|
||||||
|
// println(ret, HEX);
|
||||||
|
uartDmaReadCount++;
|
||||||
|
|
||||||
|
if (uartDmaRestartCount > 0)
|
||||||
|
{
|
||||||
|
// process previouse buffer
|
||||||
|
uartDmaRestartCount--;
|
||||||
|
|
||||||
|
// last char, then reset read count to start at new writer position
|
||||||
|
if (uartDmaRestartCount == 0)
|
||||||
|
uartDmaReadCount = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t RP2040ArduinoPlatform::writeUart(const uint8_t data)
|
||||||
|
{
|
||||||
|
if (uartDmaChannel == -1)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
// print("> ");
|
||||||
|
// println(data, HEX);
|
||||||
|
while (!uart_is_writable(uart0))
|
||||||
|
;
|
||||||
|
uart_putc_raw(uart0, data);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RP2040ArduinoPlatform::closeUart()
|
||||||
|
{
|
||||||
|
if (uartDmaChannel >= 0)
|
||||||
|
{
|
||||||
|
dma_channel_cleanup(uartDmaChannel);
|
||||||
|
irq_set_enabled(DMA_IRQ_0, false);
|
||||||
|
uart_deinit(uart0);
|
||||||
|
uartDmaChannel = -1;
|
||||||
|
uartDmaReadCount = 0;
|
||||||
|
uartDmaRestartCount = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
uint32_t RP2040ArduinoPlatform::uniqueSerialNumber()
|
uint32_t RP2040ArduinoPlatform::uniqueSerialNumber()
|
||||||
{
|
{
|
||||||
pico_unique_board_id_t id; // 64Bit unique serial number from the QSPI flash
|
pico_unique_board_id_t id; // 64Bit unique serial number from the QSPI flash
|
||||||
@ -376,5 +560,3 @@ bool RP2040ArduinoPlatform::sendBytesUniCast(uint32_t addr, uint16_t port, uint8
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
@ -58,6 +58,22 @@
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if USE_KNX_DMA_UART == 1
|
||||||
|
#define KNX_DMA_UART uart1
|
||||||
|
#define KNX_DMA_UART_IRQ UART1_IRQ
|
||||||
|
#define KNX_DMA_UART_DREQ DREQ_UART1_RX
|
||||||
|
#else
|
||||||
|
#define KNX_DMA_UART uart0
|
||||||
|
#define KNX_DMA_UART_IRQ UART0_IRQ
|
||||||
|
#define KNX_DMA_UART_DREQ DREQ_UART0_RX
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if USE_KNX_DMA_IRQ == 1
|
||||||
|
#define KNX_DMA_IRQ DMA_IRQ_1
|
||||||
|
#else
|
||||||
|
#define KNX_DMA_IRQ DMA_IRQ_0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
class RP2040ArduinoPlatform : public ArduinoPlatform
|
class RP2040ArduinoPlatform : public ArduinoPlatform
|
||||||
{
|
{
|
||||||
@ -67,8 +83,19 @@ public:
|
|||||||
|
|
||||||
// uart
|
// uart
|
||||||
void knxUartPins(pin_size_t rxPin, pin_size_t txPin);
|
void knxUartPins(pin_size_t rxPin, pin_size_t txPin);
|
||||||
void setupUart();
|
void setupUart() override;
|
||||||
virtual bool overflowUart();
|
bool overflowUart() override;
|
||||||
|
#ifdef USE_KNX_DMA_UART
|
||||||
|
int uartAvailable() override;
|
||||||
|
void closeUart() override;
|
||||||
|
void knxUart( HardwareSerial* serial) override {};
|
||||||
|
HardwareSerial* knxUart() override { return nullptr; };
|
||||||
|
size_t writeUart(const uint8_t data) override;
|
||||||
|
size_t writeUart(const uint8_t* buffer, size_t size) override { return 0; };
|
||||||
|
int readUart() override;
|
||||||
|
size_t readBytesUart(uint8_t* buffer, size_t length) override { return 0; };
|
||||||
|
void flushUart() override {};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
// unique serial number
|
// unique serial number
|
||||||
|
Loading…
Reference in New Issue
Block a user