1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
typedef struct { uint16 rxBuf[HAL_UART_DMA_RX_MAX]; #if HAL_UART_DMA_RX_MAX < 256 uint8 rxHead; uint8 rxTail; #else uint16 rxHead; uint16 rxTail; #endif uint8 rxTick; uint8 rxShdw; uint8 txBuf[2][HAL_UART_DMA_TX_MAX]; #if HAL_UART_DMA_TX_MAX < 256 uint8 txIdx[2]; #else uint16 txIdx[2]; #endif volatile uint8 txSel; uint8 txMT; uint8 txTick; // 1-character time in 32kHz ticks according to baud rate, // to be used in calculating time lapse since DMA ISR // to allow delay margin before start firing DMA, so that // DMA does not overwrite UART DBUF of previous packet volatile uint8 txShdw; // Sleep Timer LSB shadow. volatile uint8 txShdwValid; // TX shadow value is valid uint8 txDMAPending; // UART TX DMA is pending halUARTCBack_t uartCB; } uartDMACfg_t; |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
|
static uint16 HalUARTWriteDMA(uint8 *buf, uint16 len) { uint16 cnt; halIntState_t his; uint8 txIdx, txSel; // Enforce all or none. if ((len + dmaCfg.txIdx[dmaCfg.txSel]) > HAL_UART_DMA_TX_MAX) { return 0; } HAL_ENTER_CRITICAL_SECTION(his); txSel = dmaCfg.txSel; txIdx = dmaCfg.txIdx[txSel]; HAL_EXIT_CRITICAL_SECTION(his); for (cnt = 0; cnt < len; cnt++) { dmaCfg.txBuf[txSel][txIdx++] = buf[cnt]; } HAL_ENTER_CRITICAL_SECTION(his); if (txSel != dmaCfg.txSel) { HAL_EXIT_CRITICAL_SECTION(his); txSel = dmaCfg.txSel; txIdx = dmaCfg.txIdx[txSel]; for (cnt = 0; cnt < len; cnt++) { dmaCfg.txBuf[txSel][txIdx++] = buf[cnt]; } HAL_ENTER_CRITICAL_SECTION(his); } dmaCfg.txIdx[txSel] = txIdx; if (dmaCfg.txIdx[(txSel ^ 1)] == 0) { // TX DMA is expected to be fired dmaCfg.txDMAPending = TRUE; } HAL_EXIT_CRITICAL_SECTION(his); return cnt; } |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
static uint16 HalUARTReadDMA(uint8 *buf, uint16 len) { uint16 cnt; for (cnt = 0; cnt < len; cnt++) { if (!HAL_UART_DMA_NEW_RX_BYTE(dmaCfg.rxHead)) { break ; } *buf++ = HAL_UART_DMA_GET_RX_BYTE(dmaCfg.rxHead); HAL_UART_DMA_CLR_RX_BYTE(dmaCfg.rxHead); if (++(dmaCfg.rxHead) >= HAL_UART_DMA_RX_MAX) { dmaCfg.rxHead = 0; } } PxOUT &= ~HAL_UART_Px_RTS; // Re-enable the flow on any read. return cnt; } |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
|
static void HalUARTPollDMA( void ) { uint16 cnt = 0; uint8 evt = 0; if (HAL_UART_DMA_NEW_RX_BYTE(dmaCfg.rxHead)) { uint16 tail = findTail(); // If the DMA has transferred in more Rx bytes, reset the Rx idle timer. if (dmaCfg.rxTail != tail) { dmaCfg.rxTail = tail; // Re-sync the shadow on any 1st byte(s) received. if (dmaCfg.rxTick == 0) { dmaCfg.rxShdw = ST0; } dmaCfg.rxTick = HAL_UART_DMA_IDLE; } else if (dmaCfg.rxTick) { // Use the LSB of the sleep timer (ST0 must be read first anyway). uint8 decr = ST0 - dmaCfg.rxShdw; if (dmaCfg.rxTick > decr) { dmaCfg.rxTick -= decr; dmaCfg.rxShdw = ST0; } else { dmaCfg.rxTick = 0; } } cnt = HalUARTRxAvailDMA(); } else { dmaCfg.rxTick = 0; } if (cnt >= HAL_UART_DMA_FULL) { evt = HAL_UART_RX_FULL; } else if (cnt >= HAL_UART_DMA_HIGH) { evt = HAL_UART_RX_ABOUT_FULL; PxOUT |= HAL_UART_Px_RTS; } else if (cnt && !dmaCfg.rxTick) { evt = HAL_UART_RX_TIMEOUT; } if (dmaCfg.txMT) { dmaCfg.txMT = FALSE; evt |= HAL_UART_TX_EMPTY; } if (dmaCfg.txShdwValid) { uint8 decr = ST0; decr -= dmaCfg.txShdw; if (decr > dmaCfg.txTick) { // No protection for txShdwValid is required // because while the shadow was valid, DMA ISR cannot be triggered // to cause concurrent access to this variable. dmaCfg.txShdwValid = FALSE; } } if (dmaCfg.txDMAPending && !dmaCfg.txShdwValid) { // UART TX DMA is expected to be fired and enough time has lapsed since last DMA ISR // to know that DBUF can be overwritten halDMADesc_t *ch = HAL_DMA_GET_DESC1234(HAL_DMA_CH_TX); halIntState_t intState; // Clear the DMA pending flag dmaCfg.txDMAPending = FALSE; HAL_DMA_SET_SOURCE(ch, dmaCfg.txBuf[dmaCfg.txSel]); HAL_DMA_SET_LEN(ch, dmaCfg.txIdx[dmaCfg.txSel]); dmaCfg.txSel ^= 1; HAL_ENTER_CRITICAL_SECTION(intState); HAL_DMA_ARM_CH(HAL_DMA_CH_TX); do { asm( "NOP" ); } while (!HAL_DMA_CH_ARMED(HAL_DMA_CH_TX)); HAL_DMA_CLEAR_IRQ(HAL_DMA_CH_TX); HAL_DMA_MAN_TRIGGER(HAL_DMA_CH_TX); HAL_EXIT_CRITICAL_SECTION(intState); } if (evt && (dmaCfg.uartCB != NULL)) { dmaCfg.uartCB(HAL_UART_DMA-1, evt); } } |
1
2
3
4
|
#define HAL_UART_DMA_FULL (HAL_UART_DMA_RX_MAX - 16) #define HAL_UART_DMA_HIGH (HAL_UART_DMA_RX_MAX / 2 - 16) #define HAL_UART_DMA_IDLE (6 * HAL_UART_MSECS_TO_TICKS) dmaCfg.txMT |