23 #ifdef SATCAT5_SAMV71_UART_WRST
24 #define SATCAT5_SAMV71_UART_WRST=1
28 static const u32 CACHE_LINESIZE = 32;
29 static const u32 CACHE_ADDRMASK = 0xFFFFFFE0;
44 static bool XDMAC_RESET_DONE =
false;
50 static usart_conf get_conf(
const Usart* usart) {
51 if (usart == USART0) {
52 return { ID_USART0, USART0_IRQn,
true, 0, 1,
53 XDMAC_CHANNEL_HWID_USART0_TX, XDMAC_CHANNEL_HWID_USART0_RX };
54 }
else if (usart == USART1) {
55 return { ID_USART1, USART1_IRQn,
true, 2, 3,
56 XDMAC_CHANNEL_HWID_USART1_TX, XDMAC_CHANNEL_HWID_USART1_RX };
57 }
else if (usart == USART2) {
58 return { ID_USART2, USART2_IRQn,
true, 4, 5,
59 XDMAC_CHANNEL_HWID_USART2_TX, XDMAC_CHANNEL_HWID_USART2_RX };
60 }
else if (usart == (Usart*) UART0) {
61 return { ID_UART0, UART0_IRQn,
false, 6, 7,
62 XDMAC_CHANNEL_HWID_UART0_TX, XDMAC_CHANNEL_HWID_UART0_RX };
63 }
else if (usart == (Usart*) UART1) {
64 return { ID_UART1, UART1_IRQn,
false, 8, 9,
65 XDMAC_CHANNEL_HWID_UART1_TX, XDMAC_CHANNEL_HWID_UART1_RX };
66 }
else if (usart == (Usart*) UART2) {
67 return { ID_UART2, UART2_IRQn,
false, 10, 11,
68 XDMAC_CHANNEL_HWID_UART2_TX, XDMAC_CHANNEL_HWID_UART2_RX };
69 }
else if (usart == (Usart*) UART3) {
70 return { ID_UART3, UART3_IRQn,
false, 12, 13,
71 XDMAC_CHANNEL_HWID_UART3_TX, XDMAC_CHANNEL_HWID_UART3_RX };
72 }
else if (usart == (Usart*) UART4) {
73 return { ID_UART4, UART4_IRQn,
false, 14, 15,
74 XDMAC_CHANNEL_HWID_UART4_TX, XDMAC_CHANNEL_HWID_UART4_RX };
76 return { ID_PERIPH_COUNT, PERIPH_COUNT_IRQn,
false, 0, 0, 0, 0 };
81 UsartSamv71::UsartSamv71(Usart* usart,
unsigned baud_hz,
unsigned poll_ms,
82 u8* txbuff,
unsigned tx_nbytes, u8* rxbuff,
unsigned rx_nbytes,
83 u8* rxdma0, u8* rxdma1,
unsigned rxdma_nbytes,
bool fc_on)
84 :
BufferedIO(txbuff, tx_nbytes, 0, rxbuff, rx_nbytes, 0)
91 , m_rxdma_nbytes(rxdma_nbytes)
96 if (ids.clk_id == ID_PERIPH_COUNT) {
100 m_tx_dma_ch = ids.tx_dma_ch;
101 m_rx_dma_ch = ids.rx_dma_ch;
104 if (!XDMAC_RESET_DONE) {
105 XDMAC->XDMAC_GD = 0xFFFFFFFF;
106 XDMAC->XDMAC_GID = 0xFFFFFFFF;
107 XDMAC->XDMAC_GSWR = 1;
108 XDMAC_RESET_DONE =
true;
112 sysclk_enable_peripheral_clock(ids.clk_id);
113 pmc_enable_periph_clk(ID_XDMAC);
129 if (!m_usart) {
return; }
132 sam_usart_opt_t opt =
135 .char_length = US_MR_CHRL_8_BIT,
136 .parity_type = US_MR_PAR_NO,
137 .stop_bits = US_MR_NBSTOP_1_BIT,
138 .channel_mode = US_MR_USART_MODE_NORMAL
142 m_rts_en = get_conf(m_usart).supports_fc && rts_en;
143 m_cts_en = get_conf(m_usart).supports_fc && cts_en;
145 usart_init_hw_handshaking(m_usart, &opt, sysclk_get_peripheral_hz());
147 usart_init_rs232(m_usart, &opt, sysclk_get_peripheral_hz());
149 if (m_rts_en && !((XDMAC->XDMAC_GS >> m_rx_dma_ch) & 0x1)) {
154 usart_enable_tx(m_usart);
155 usart_enable_rx(m_usart);
160 if (XDMAC->XDMAC_CHID[m_rx_dma_ch].XDMAC_CIS & XDMAC_CIS_BIS) {
164 if (XDMAC->XDMAC_CHID[m_tx_dma_ch].XDMAC_CIS & XDMAC_CIS_BIS) {
174 if (!m_usart) {
return; }
177 if ((XDMAC->XDMAC_GS >> m_tx_dma_ch) & 0x1) {
return; }
184 if (!m_txdma_nbytes) {
return; }
186 #ifdef SATCAT5_SAMV71_UART_WRST
191 #if SATCAT5_SAMV71_UART_DCACHE
193 u32* cache_addr = (u32*) ((u32)
m_tx.
peek(m_txdma_nbytes) & CACHE_ADDRMASK);
194 SCB_CleanDCache_by_Addr(cache_addr, m_txdma_nbytes + CACHE_LINESIZE-1);
198 XDMAC->XDMAC_CHID[m_tx_dma_ch].XDMAC_CSA = (u32)
m_tx.
peek(m_txdma_nbytes);
199 XDMAC->XDMAC_CHID[m_tx_dma_ch].XDMAC_CUBC = (u32) m_txdma_nbytes;
200 XDMAC->XDMAC_GE = (1 << m_tx_dma_ch);
209 if (!m_usart) {
return; }
214 if (((XDMAC->XDMAC_GS >> m_rx_dma_ch) & 0x1) &&
215 XDMAC->XDMAC_CHID[m_rx_dma_ch].XDMAC_CUBC == m_rxdma_nbytes) {
return; }
221 AtomicLock lock(
"UsartSamv71::poll_rx_dma()");
223 m_rxdma_buffidx = 1 - m_rxdma_buffidx;
225 XDMAC->XDMAC_GD = (1 << m_rx_dma_ch);
226 while ((XDMAC->XDMAC_GS >> m_rx_dma_ch) & 0x1) {}
227 unsigned nbytes_wr = m_rxdma_nbytes -
228 XDMAC->XDMAC_CHID[m_rx_dma_ch].XDMAC_CUBC;
229 XDMAC->XDMAC_CHID[m_rx_dma_ch].XDMAC_CDA = (u32)
get_rxdma_buff();
230 XDMAC->XDMAC_CHID[m_rx_dma_ch].XDMAC_CUBC = m_rxdma_nbytes;
231 XDMAC->XDMAC_GE = (1 << m_rx_dma_ch);
235 #ifdef SATCAT5_SAMV71_UART_WRST
241 if (!nbytes_wr) {
return; }
242 #if SATCAT5_SAMV71_UART_DCACHE
243 u32* cache_addr = (u32*) ((u32) read_buff & CACHE_ADDRMASK);
244 SCB_InvalidateDCache_by_Addr(cache_addr, nbytes_wr + CACHE_LINESIZE-1);
256 xdmac_channel_config_t tx_dma_conf =
260 .mbr_da = (u32)&(m_usart->US_THR),
261 .mbr_cfg = XDMAC_CC_TYPE_PER_TRAN |
262 XDMAC_CC_MBSIZE_SINGLE |
263 XDMAC_CC_DSYNC_MEM2PER |
264 XDMAC_CC_CSIZE_CHK_1 |
265 XDMAC_CC_DWIDTH_BYTE |
266 XDMAC_CC_SIF_AHB_IF0 |
267 XDMAC_CC_DIF_AHB_IF1 |
268 XDMAC_CC_SAM_INCREMENTED_AM |
269 XDMAC_CC_DAM_FIXED_AM |
270 XDMAC_CC_PERID(tx_perid),
280 xdmac_channel_config_t rx_dma_conf =
282 .mbr_ubc = m_rxdma_nbytes,
283 .mbr_sa = (u32) &(m_usart->US_RHR),
285 .mbr_cfg = XDMAC_CC_TYPE_PER_TRAN |
286 XDMAC_CC_MBSIZE_SINGLE |
287 XDMAC_CC_DSYNC_PER2MEM |
288 XDMAC_CC_CSIZE_CHK_1 |
289 XDMAC_CC_DWIDTH_BYTE |
290 XDMAC_CC_SIF_AHB_IF1 |
291 XDMAC_CC_DIF_AHB_IF0 |
292 XDMAC_CC_SAM_FIXED_AM |
293 XDMAC_CC_DAM_INCREMENTED_AM |
294 XDMAC_CC_PERID(rx_perid),
302 xdmac_channel_disable(XDMAC, m_tx_dma_ch);
303 xdmac_channel_disable(XDMAC, m_rx_dma_ch);
304 xdmac_configure_transfer(XDMAC, m_tx_dma_ch, &tx_dma_conf);
305 xdmac_configure_transfer(XDMAC, m_rx_dma_ch, &rx_dma_conf);
306 xdmac_enable_interrupt(XDMAC, m_rx_dma_ch);
307 xdmac_channel_enable_interrupt(XDMAC, m_rx_dma_ch, XDMAC_CIE_BIE);
308 xdmac_enable_interrupt(XDMAC, m_tx_dma_ch);
309 xdmac_channel_enable_interrupt(XDMAC, m_tx_dma_ch, XDMAC_CIE_BIE);
317 if (!m_rts_en) {
return; }
319 m_usart->US_CR = US_CR_RTSEN;
321 m_usart->US_CR = US_CR_RTSDIS;
330 m_usart->US_CR = US_CR_RTSDIS;
332 m_usart->US_CR = US_CR_RTSEN;
Extensible transmit and receive buffer.
satcat5::io::PacketBuffer m_tx
Transmit data (user writes, child reads)
satcat5::io::PacketBuffer m_rx
Receive data (user reads, child writes)
const u8 * peek(unsigned nbytes) const
Peek nbytes into the circular buffer.
unsigned get_peek_ready() const
Find the longest available contiguous segment that can be requested by peek().
bool write_finalize() override
Mark end of frame and release temporary working data.
void write_bytes(unsigned nbytes, const void *src) override
Write 0 or more bytes from a buffer.
bool read_consume(unsigned nbytes) override
Read and discard 0 or more bytes.
void release()
Optionally release this lock before the destructor is called.
An "Always" object is polled whenever service() is called.
void poll_register()
Register this pollable object, called by the constructor.
void timer_every(unsigned msec)
Configure a repeating notification every X milliseconds.
Interrupt handler interface for the Microchip SAM V71.
io::BufferedIO interface for the SAMV71 USART and UART peripherals.
void rts_low()
Drive the RTS signal high/low if flow-control is on.
void rts_high()
Drive the RTS signal high/low if flow-control is on.
void configure(unsigned baud_hz, bool rts_en, bool cts_en)
Set baud rate and RTS/CTS enable.
void configure_xdmac(u32 tx_dma_ch, u32 rx_dma_ch)
Initial setup of the TX/RX DMA controllers.
void poll_tx_dma()
Poll the RX DMA engine for new data received.
void poll_rx_dma()
Poll the TX DMA engine for unsent data to transmit.
u8 * get_rxdma_buff()
Get the RX buffer the DMA is currently writing to.
void irq_event() override
IRQ indicates the RX DMA is full or the TX DMA is empty.
SAMV71 UART/USART serial interface driver.