31
31
32
32
#if CFG_TUSB_MCU == OPT_MCU_STM32G4
33
33
#include "stm32g4xx.h"
34
- #include "stm32g4xx_hal_dma .h"
34
+ #include "stm32g4xx_ll_dma .h" // for UCLP REQID
35
35
#else
36
36
#error "Unsupported STM32 family"
37
37
#endif
40
40
//
41
41
//--------------------------------------------------------------------+
42
42
43
+ enum {
44
+ IMR_ATTACHED = UCPD_IMR_TXMSGDISCIE | UCPD_IMR_TXMSGSENTIE | UCPD_IMR_TXMSGABTIE | UCPD_IMR_TXUNDIE |
45
+ UCPD_IMR_RXHRSTDETIE | UCPD_IMR_RXOVRIE | UCPD_IMR_RXMSGENDIE | UCPD_IMR_RXORDDETIE |
46
+ UCPD_IMR_HRSTDISCIE | UCPD_IMR_HRSTSENTIE | UCPD_IMR_FRSEVTIE
47
+ };
48
+
43
49
#define PHY_SYNC1 0x18u
44
50
#define PHY_SYNC2 0x11u
45
51
#define PHY_SYNC3 0x06u
57
63
58
64
59
65
static uint8_t rx_buf [262 ] TU_ATTR_ALIGNED (4 );
60
- static uint32_t rx_count = 0 ;
61
-
62
66
static uint8_t tx_buf [262 ] TU_ATTR_ALIGNED (4 );
63
- static uint32_t tx_count ;
67
+ static uint32_t tx_index ;
64
68
65
- #define CFG_TUC_STM32_DMA_RX { DMA1_Channel1 }
66
- // #define CFG_TUC_STM32_DMA_TX { DMA1_Channel2 }
69
+ // address of DMA channel rx, tx for each port
70
+ #define CFG_TUC_STM32_DMA { { DMA1_Channel1_BASE, DMA1_Channel2_BASE } }
67
71
68
- #ifdef CFG_TUC_STM32_DMA_RX
69
- static DMA_Channel_TypeDef * dma_rx_arr [TUP_TYPEC_RHPORTS_NUM ] = CFG_TUC_STM32_DMA_RX ;
72
+ //--------------------------------------------------------------------+
73
+ // DMA
74
+ //--------------------------------------------------------------------+
70
75
71
- TU_ATTR_ALWAYS_INLINE static inline
72
- void dma_rx_start (uint8_t rhport )
73
- {
74
- DMA_Channel_TypeDef * dma_rx_ch = dma_rx_arr [rhport ];
76
+ static const uint32_t dma_addr_arr [TUP_TYPEC_RHPORTS_NUM ][2 ] = CFG_TUC_STM32_DMA ;
75
77
76
- dma_rx_ch -> CMAR = (uint32_t ) rx_buf ;
77
- dma_rx_ch -> CNDTR = sizeof (rx_buf );
78
- dma_rx_ch -> CCR |= DMA_CCR_EN ;
78
+ TU_ATTR_ALWAYS_INLINE static inline uint32_t dma_get_addr (uint8_t rhport , bool is_rx ) {
79
+ return dma_addr_arr [rhport ][is_rx ? 0 : 1 ];
79
80
}
80
- #endif
81
81
82
- #ifdef CFG_TUC_STM32_DMA_TX
83
- static DMA_Channel_TypeDef * dma_tx_arr [TUP_TYPEC_RHPORTS_NUM ] = CFG_TUC_STM32_DMA_TX ;
84
- #endif
82
+ static void dma_init (uint8_t rhport , bool is_rx ) {
83
+ uint32_t dma_addr = dma_get_addr (rhport , is_rx );
84
+ DMA_Channel_TypeDef * dma_ch = (DMA_Channel_TypeDef * ) dma_addr ;
85
+ uint32_t req_id ;
86
+
87
+ if (is_rx ) {
88
+ // Peripheral -> Memory, Memory inc, 8-bit, High priority
89
+ dma_ch -> CCR = DMA_CCR_MINC | DMA_CCR_PL_1 ;
90
+ dma_ch -> CPAR = (uint32_t ) & UCPD1 -> RXDR ;
91
+
92
+ req_id = LL_DMAMUX_REQ_UCPD1_RX ;
93
+ } else {
94
+ // Memory -> Peripheral, Memory inc, 8-bit, High priority
95
+ dma_ch -> CCR = DMA_CCR_MINC | DMA_CCR_PL_1 | DMA_CCR_DIR ;
96
+ dma_ch -> CPAR = (uint32_t ) & UCPD1 -> TXDR ;
97
+
98
+ req_id = LL_DMAMUX_REQ_UCPD1_TX ;
99
+ }
100
+
101
+ // find and set up mux channel TODO support mcu with multiple DMAMUXs
102
+ enum {
103
+ CH_DIFF = DMA1_Channel2_BASE - DMA1_Channel1_BASE
104
+ };
105
+ uint32_t mux_ch_num ;
106
+
107
+ #ifdef DMA2_BASE
108
+ if (dma_addr > DMA2_BASE ) {
109
+ mux_ch_num = 8 * ((dma_addr - DMA2_Channel1_BASE ) / CH_DIFF );
110
+ } else
111
+ #endif
112
+ {
113
+ mux_ch_num = (dma_addr - DMA1_Channel1_BASE ) / CH_DIFF ;
114
+ }
115
+
116
+ DMAMUX_Channel_TypeDef * mux_ch = DMAMUX1_Channel0 + mux_ch_num ;
117
+
118
+ uint32_t mux_ccr = mux_ch -> CCR & ~(DMAMUX_CxCR_DMAREQ_ID );
119
+ mux_ccr |= req_id ;
120
+ mux_ch -> CCR = mux_ccr ;
121
+ }
122
+
123
+ TU_ATTR_ALWAYS_INLINE static inline void dma_start (uint8_t rhport , bool is_rx , void const * buf , uint16_t len ) {
124
+ DMA_Channel_TypeDef * dma_ch = (DMA_Channel_TypeDef * ) dma_get_addr (rhport , is_rx );
125
+
126
+ dma_ch -> CMAR = (uint32_t ) buf ;
127
+ dma_ch -> CNDTR = len ;
128
+ dma_ch -> CCR |= DMA_CCR_EN ;
129
+ }
130
+
131
+ TU_ATTR_ALWAYS_INLINE static inline void dma_stop (uint8_t rhport , bool is_rx ) {
132
+ DMA_Channel_TypeDef * dma_ch = (DMA_Channel_TypeDef * ) dma_get_addr (rhport , is_rx );
133
+ dma_ch -> CCR &= ~DMA_CCR_EN ;
134
+ }
135
+
136
+ TU_ATTR_ALWAYS_INLINE static inline void dma_rx_start (uint8_t rhport ) {
137
+ dma_start (rhport , true, rx_buf , sizeof (rx_buf ));
138
+ }
139
+
140
+ TU_ATTR_ALWAYS_INLINE static inline void dma_tx_start (uint8_t rhport , void const * buf , uint16_t len ) {
141
+ UCPD1 -> TX_ORDSET = PHY_ORDERED_SET_SOP ;
142
+ UCPD1 -> TX_PAYSZ = len ;
143
+ dma_start (rhport , false, buf , len );
144
+ }
85
145
86
146
//--------------------------------------------------------------------+
87
147
//
88
148
//--------------------------------------------------------------------+
89
- #include "stm32g4xx_ll_dma.h"
149
+
90
150
91
151
bool tcd_init (uint8_t rhport , tusb_typec_port_type_t port_type ) {
92
152
(void ) rhport ;
93
153
94
- #ifdef CFG_TUC_STM32_DMA_RX
95
- // Init DMA
96
- DMA_Channel_TypeDef * dma_rx_ch = dma_rx_arr [rhport ];
97
-
98
- // Peripheral -> Memory, Memory inc, 8-bit, High priority
99
- dma_rx_ch -> CCR = DMA_CCR_MINC | DMA_CCR_PL_1 ;
100
- dma_rx_ch -> CPAR = (uint32_t ) & UCPD1 -> RXDR ;
101
-
102
- LL_DMA_SetPeriphRequest (DMA1 , LL_DMA_CHANNEL_1 , LL_DMAMUX_REQ_UCPD1_RX );
103
- #endif
154
+ // Init DMA for RX, TX
155
+ dma_init (rhport , true);
156
+ dma_init (rhport , false);
104
157
105
158
// Initialization phase: CFG1
106
159
UCPD1 -> CFG1 = (0x0d << UCPD_CFG1_HBITCLKDIV_Pos ) | (0x10 << UCPD_CFG1_IFRGAP_Pos ) | (0x07 << UCPD_CFG1_TRANSWIN_Pos ) |
107
- (0x01 << UCPD_CFG1_PSC_UCPDCLK_Pos ) | (0x1f << UCPD_CFG1_RXORDSETEN_Pos ) |
108
- (0 << UCPD_CFG1_TXDMAEN_Pos ) | (0 << UCPD_CFG1_RXDMAEN_Pos );
160
+ (0x01 << UCPD_CFG1_PSC_UCPDCLK_Pos ) | (0x1f << UCPD_CFG1_RXORDSETEN_Pos );
109
161
UCPD1 -> CFG1 |= UCPD_CFG1_UCPDEN ;
110
162
111
163
// General programming sequence (with UCPD configured then enabled)
@@ -118,8 +170,7 @@ bool tcd_init(uint8_t rhport, tusb_typec_port_type_t port_type) {
118
170
vstate_cc [0 ] = (UCPD1 -> SR >> UCPD_SR_TYPEC_VSTATE_CC1_Pos ) & 0x03 ;
119
171
vstate_cc [1 ] = (UCPD1 -> SR >> UCPD_SR_TYPEC_VSTATE_CC2_Pos ) & 0x03 ;
120
172
121
- TU_LOG1_INT (vstate_cc [0 ]);
122
- TU_LOG1_INT (vstate_cc [1 ]);
173
+ TU_LOG1 ("Initial VState CC1 = %u, CC2 = %u\r\n" , vstate_cc [0 ], vstate_cc [1 ]);
123
174
124
175
// Enable CC1 & CC2 Interrupt
125
176
UCPD1 -> IMR = UCPD_IMR_TYPECEVT1IE | UCPD_IMR_TYPECEVT2IE ;
@@ -142,7 +193,8 @@ void tcd_int_disable(uint8_t rhport) {
142
193
143
194
bool tcd_rx_start (uint8_t rhport , uint8_t * buffer , uint16_t total_bytes ) {
144
195
(void ) rhport ;
145
-
196
+ (void ) buffer ;
197
+ (void ) total_bytes ;
146
198
return true;
147
199
}
148
200
@@ -159,8 +211,6 @@ void tcd_int_handler(uint8_t rhport) {
159
211
uint32_t sr = UCPD1 -> SR ;
160
212
sr &= UCPD1 -> IMR ;
161
213
162
- // TU_LOG1("UCPD1_IRQHandler: sr = 0x%08X\n", sr);
163
-
164
214
if (sr & (UCPD_SR_TYPECEVT1 | UCPD_SR_TYPECEVT2 )) {
165
215
uint32_t vstate_cc [2 ];
166
216
vstate_cc [0 ] = (UCPD1 -> SR >> UCPD_SR_TYPEC_VSTATE_CC1_Pos ) & 0x03 ;
@@ -169,7 +219,6 @@ void tcd_int_handler(uint8_t rhport) {
169
219
TU_LOG1 ("VState CC1 = %u, CC2 = %u\n" , vstate_cc [0 ], vstate_cc [1 ]);
170
220
171
221
uint32_t cr = UCPD1 -> CR ;
172
- uint32_t cfg1 = UCPD1 -> CFG1 ;
173
222
174
223
// TODO only support SNK for now, required highest voltage for now
175
224
// Enable PHY on correct CC and disable Rd on other CC
@@ -189,28 +238,18 @@ void tcd_int_handler(uint8_t rhport) {
189
238
}
190
239
191
240
if (cr & UCPD_CR_PHYRXEN ) {
192
- // Enable Interrupt
193
- uint32_t imr = UCPD1 -> IMR ;
194
- imr |= UCPD_IMR_TXMSGDISCIE | UCPD_IMR_TXMSGSENTIE | UCPD_IMR_TXMSGABTIE | UCPD_IMR_TXUNDIE |
195
- UCPD_IMR_RXHRSTDETIE | UCPD_IMR_RXOVRIE | UCPD_IMR_RXMSGENDIE | UCPD_IMR_RXORDDETIE |
196
- UCPD_IMR_HRSTDISCIE | UCPD_IMR_HRSTSENTIE | UCPD_IMR_FRSEVTIE ;
197
-
198
- #ifdef CFG_TUC_STM32_DMA_RX
199
- cfg1 |= UCPD_CFG1_RXDMAEN ;
200
- dma_rx_start (rhport );
201
- #else
202
- imr |= UCPD_IMR_RXNEIE | UCPD_IMR_RXORDDETIE ;
203
- #endif
241
+ // Attached
242
+ UCPD1 -> IMR |= IMR_ATTACHED ;
243
+ UCPD1 -> CFG1 |= UCPD_CFG1_RXDMAEN | UCPD_CFG1_TXDMAEN ;
204
244
205
- #ifndef CFG_TUC_STM32_DMA_TX
206
- imr |= UCPD_IMR_TXISIE ;
207
- #endif
208
-
209
- UCPD1 -> IMR = imr ;
245
+ dma_rx_start ( rhport );
246
+ } else {
247
+ // Detached
248
+ UCPD1 -> CFG1 &= ~( UCPD_CFG1_RXDMAEN | UCPD_CFG1_TXDMAEN );
249
+ UCPD1 -> IMR &= ~ IMR_ATTACHED ;
210
250
}
211
251
212
252
UCPD1 -> CR = cr ;
213
- UCPD1 -> CFG1 = cfg1 ;
214
253
215
254
// ack
216
255
UCPD1 -> ICR = UCPD_ICR_TYPECEVT1CF | UCPD_ICR_TYPECEVT2CF ;
@@ -221,27 +260,15 @@ void tcd_int_handler(uint8_t rhport) {
221
260
// SOP: Start of Packet.
222
261
// UCPD1->RX_ORDSET & UCPD_RX_ORDSET_RXORDSET_Msk;
223
262
224
- // reset count when received SOP
225
- rx_count = 0 ;
226
-
227
263
// ack
228
264
UCPD1 -> ICR = UCPD_ICR_RXORDDETCF ;
229
265
}
230
266
231
- #ifndef CFG_TUC_STM32_DMA_RX
232
- if (sr & UCPD_SR_RXNE ) {
233
- // TODO DMA later
234
- do {
235
- rx_buf [rx_count ++ ] = UCPD1 -> RXDR ;
236
- } while (UCPD1 -> SR & UCPD_SR_RXNE );
237
-
238
- // no ack needed
239
- }
240
- #endif
241
-
242
267
// Received full message
243
268
if (sr & UCPD_SR_RXMSGEND ) {
244
269
270
+ dma_stop (rhport , true);
271
+
245
272
// Skip if CRC failed
246
273
if (!(sr & UCPD_SR_RXERR )) {
247
274
uint32_t payload_size = UCPD1 -> RX_PAYSZ ;
@@ -251,26 +278,23 @@ void tcd_int_handler(uint8_t rhport) {
251
278
(* (tusb_pd_header_t * ) tx_buf ) = (tusb_pd_header_t ) {
252
279
.msg_type = TUSB_PD_CTRL_GOOD_CRC ,
253
280
.data_role = 0 , // UFP
254
- .specs_rev = TUSB_PD_REV30 ,
281
+ .specs_rev = TUSB_PD_REV20 ,
255
282
.power_role = 0 , // Sink
256
283
.msg_id = rx_header -> msg_id ,
257
284
.n_data_obj = 0 ,
258
285
.extended = 0
259
286
};
260
- tx_count = 0 ;
261
287
262
288
// response with good crc
263
- UCPD1 -> TX_ORDSET = PHY_ORDERED_SET_SOP ;
264
- UCPD1 -> TX_PAYSZ = 2 ;
265
- UCPD1 -> CR |= UCPD_CR_TXSEND ; // will trigger TXIS interrupt
289
+ dma_tx_start ( rhport , tx_buf , 2 ) ;
290
+
291
+ UCPD1 -> CR |= UCPD_CR_TXSEND ;
266
292
267
- // notify stack after good crc ?
293
+ // notify stack
268
294
}
269
295
270
- #ifdef CFG_TUC_STM32_DMA_RX
271
296
// prepare next receive
272
297
dma_rx_start (rhport );
273
- #endif
274
298
275
299
// ack
276
300
UCPD1 -> ICR = UCPD_ICR_RXMSGENDCF ;
@@ -283,34 +307,19 @@ void tcd_int_handler(uint8_t rhport) {
283
307
}
284
308
285
309
//------------- TX -------------//
286
- if (sr & UCPD_SR_TXIS ) {
287
- // TU_LOG1("TXIS\n");
288
-
289
- // TODO DMA later
290
- do {
291
- UCPD1 -> TXDR = tx_buf [tx_count ++ ];
292
- } while (UCPD1 -> SR & UCPD_SR_TXIS );
293
-
294
- // no ack needed
295
- }
296
-
297
310
if (sr & UCPD_SR_TXMSGSENT ) {
298
311
// all byte sent
299
- TU_LOG1 ( "TXMSGSENT\n" );
312
+ dma_stop ( rhport , false );
300
313
301
314
// ack
302
315
UCPD1 -> ICR = UCPD_ICR_TXMSGSENTCF ;
303
316
}
304
317
305
- // if (sr & UCPD_SR_RXNE) {
306
- // uint8_t data = UCPD1->RXDR;
307
- // pd_rx_buf[pd_rx_count++] = data;
308
- // TU_LOG1_HEX(data);
309
- // }
310
-
311
- // else {
312
- // TU_LOG_LOCATION();
313
- // }
318
+ if (sr & (UCPD_SR_TXMSGDISC | UCPD_SR_TXMSGABT | UCPD_SR_TXUND )) {
319
+ TU_LOG1 ("TX Error\n" );
320
+ dma_stop (rhport , false);
321
+ UCPD1 -> ICR = UCPD_SR_TXMSGDISC | UCPD_SR_TXMSGABT | UCPD_SR_TXUND ;
322
+ }
314
323
}
315
324
316
325
#endif
0 commit comments