Skip to content

Commit 6941a5a

Browse files
committed
wrap up initial PD support for G4
1 parent c285030 commit 6941a5a

File tree

4 files changed

+195
-108
lines changed

4 files changed

+195
-108
lines changed

examples/typec/power_delivery/src/main.c

Lines changed: 89 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,8 @@ int main(void)
6262
while (1) {
6363
led_blinking_task();
6464

65-
// tuc_task();
65+
// tinyusb typec task
66+
tuc_task();
6667
}
6768
}
6869

@@ -73,6 +74,93 @@ void app_main(void)
7374
}
7475
#endif
7576

77+
//--------------------------------------------------------------------+
78+
// TypeC PD callbacks
79+
//--------------------------------------------------------------------+
80+
81+
bool tuc_pd_data_received_cb(uint8_t rhport, pd_header_t const* header, uint8_t const* dobj, uint8_t const* p_end) {
82+
switch (header->msg_type) {
83+
case PD_DATA_SOURCE_CAP: {
84+
printf("PD Source Capabilities\r\n");
85+
// Examine source capability and select a suitable PDO (starting from 1 with safe5v)
86+
uint8_t obj_pos = 1;
87+
88+
for(size_t i=0; i<header->n_data_obj; i++) {
89+
TU_VERIFY(dobj < p_end);
90+
uint32_t const pdo = tu_le32toh(tu_unaligned_read32(dobj));
91+
92+
switch ((pdo >> 30) & 0x03ul) {
93+
case PD_PDO_TYPE_FIXED: {
94+
pd_pdo_fixed_t const* fixed = (pd_pdo_fixed_t const*) &pdo;
95+
printf("[Fixed] %u mV %u mA\r\n", fixed->voltage_50mv*50, fixed->current_max_10ma*10);
96+
break;
97+
}
98+
99+
case PD_PDO_TYPE_BATTERY:
100+
break;
101+
102+
case PD_PDO_TYPE_VARIABLE:
103+
break;
104+
105+
case PD_PDO_TYPE_APDO:
106+
break;
107+
}
108+
109+
dobj += 4;
110+
}
111+
112+
//------------- Response with selected PDO -------------//
113+
// Be careful and make sure your board can withstand the selected PDO voltage other than safe5v e.g 12v or 20v
114+
115+
// Send request with selected PDO position as response to Source Cap
116+
pd_rdo_fixed_variable_t rdo = {
117+
.current_extremum_10ma = 50, // max 500mA
118+
.current_operate_10ma = 30, // 300mA
119+
.reserved = 0,
120+
.epr_mode_capable = 0,
121+
.unchunked_ext_msg_support = 0,
122+
.no_usb_suspend = 0,
123+
.usb_comm_capable = 1,
124+
.capability_mismatch = 0,
125+
.give_back_flag = 0, // exteremum is max
126+
.object_position = obj_pos,
127+
};
128+
129+
tuc_msg_request(rhport, &rdo);
130+
131+
break;
132+
}
133+
134+
default: break;
135+
}
136+
137+
return true;
138+
}
139+
140+
bool tuc_pd_control_received_cb(uint8_t rhport, pd_header_t const* header) {
141+
switch (header->msg_type) {
142+
case PD_CTRL_ACCEPT:
143+
printf("PD Request Accepted\r\n");
144+
// preparing for power transition
145+
break;
146+
147+
case PD_CTRL_REJECT:
148+
printf("PD Request Rejected\r\n");
149+
// try to negotiate further power
150+
break;
151+
152+
case PD_CTRL_PS_READY:
153+
printf("PD Power Ready\r\n");
154+
// Source is ready to supply power
155+
break;
156+
157+
default:
158+
break;
159+
}
160+
161+
return true;
162+
}
163+
76164
//--------------------------------------------------------------------+
77165
// BLINKING TASK
78166
//--------------------------------------------------------------------+

src/typec/tcd.h

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,7 @@ enum {
4848
TCD_EVENT_TX_COMPLETE,
4949
};
5050

51-
52-
typedef struct {
51+
typedef struct TU_ATTR_PACKED {
5352
uint8_t rhport;
5453
uint8_t event_id;
5554

@@ -58,10 +57,10 @@ typedef struct {
5857
uint8_t cc_state[2];
5958
} cc_changed;
6059

61-
struct {
62-
uint16_t xferred_bytes;
63-
uint8_t result;
64-
} rx_complete;
60+
struct TU_ATTR_PACKED {
61+
uint16_t result : 2;
62+
uint16_t xferred_bytes : 14;
63+
} xfer_complete;
6564
};
6665

6766
} tcd_event_t;;
@@ -114,7 +113,7 @@ void tcd_event_rx_complete(uint8_t rhport, uint16_t xferred_bytes, uint8_t resul
114113
tcd_event_t event = {
115114
.rhport = rhport,
116115
.event_id = TCD_EVENT_RX_COMPLETE,
117-
.rx_complete = {
116+
.xfer_complete = {
118117
.xferred_bytes = xferred_bytes,
119118
.result = result
120119
}
@@ -128,7 +127,7 @@ void tcd_event_tx_complete(uint8_t rhport, uint16_t xferred_bytes, uint8_t resul
128127
tcd_event_t event = {
129128
.rhport = rhport,
130129
.event_id = TCD_EVENT_TX_COMPLETE,
131-
.rx_complete = {
130+
.xfer_complete = {
132131
.xferred_bytes = xferred_bytes,
133132
.result = result
134133
}

src/typec/utcd.c

Lines changed: 79 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,12 @@ static bool _utcd_inited = false;
5252
static bool _port_inited[TUP_TYPEC_RHPORTS_NUM];
5353

5454
// Max possible PD size is 262 bytes
55-
static uint8_t _rx_buf[262] TU_ATTR_ALIGNED(4);
56-
static uint8_t _tx_buf[100] TU_ATTR_ALIGNED(4);
55+
static uint8_t _rx_buf[64] TU_ATTR_ALIGNED(4);
56+
static uint8_t _tx_buf[64] TU_ATTR_ALIGNED(4);
57+
58+
bool utcd_msg_send(uint8_t rhport, pd_header_t const* header, void const* data);
59+
bool parse_msg_data(uint8_t rhport, pd_header_t const* header, uint8_t const* dobj, uint8_t const* p_end);
60+
bool parse_msg_control(uint8_t rhport, pd_header_t const* header);
5761

5862
//--------------------------------------------------------------------+
5963
//
@@ -79,6 +83,7 @@ bool tuc_init(uint8_t rhport, uint32_t port_type) {
7983
}
8084

8185
TU_LOG_UTCD("UTCD init on port %u\r\n", rhport);
86+
TU_LOG_INT(UTCD_DEBUG, sizeof(tcd_event_t));
8287

8388
TU_ASSERT(tcd_init(rhport, port_type));
8489
tcd_int_enable(rhport);
@@ -87,137 +92,112 @@ bool tuc_init(uint8_t rhport, uint32_t port_type) {
8792
return true;
8893
}
8994

90-
//--------------------------------------------------------------------+
91-
//
92-
//--------------------------------------------------------------------+
93-
94-
bool utcd_msg_send(uint8_t rhport, pd_header_t const* header, void const* data) {
95-
// copy header
96-
memcpy(_tx_buf, header, sizeof(pd_header_t));
97-
98-
// copy data objcet if available
99-
uint16_t const n_data_obj = header->n_data_obj;
100-
if (n_data_obj > 0) {
101-
memcpy(_tx_buf + sizeof(pd_header_t), data, n_data_obj * 4);
102-
}
95+
void tuc_task_ext(uint32_t timeout_ms, bool in_isr) {
96+
(void) in_isr; // not implemented yet
10397

104-
return tcd_msg_send(rhport, _tx_buf, sizeof(pd_header_t) + n_data_obj * 4);
105-
}
98+
// Skip if stack is not initialized
99+
if (!_utcd_inited) return;
106100

107-
bool parse_message(uint8_t rhport, uint8_t const* buf, uint16_t len) {
108-
(void) rhport;
109-
uint8_t const* p_end = buf + len;
110-
pd_header_t const* header = (pd_header_t const*) buf;
111-
uint8_t const * ptr = buf + sizeof(pd_header_t);
101+
// Loop until there is no more events in the queue
102+
while (1) {
103+
tcd_event_t event;
104+
if (!osal_queue_receive(_utcd_q, &event, timeout_ms)) return;
112105

113-
if (header->n_data_obj == 0) {
114-
// control message
115-
switch (header->msg_type) {
116-
case PD_CTRL_GOOD_CRC:
106+
switch (event.event_id) {
107+
case TCD_EVENT_CC_CHANGED:
117108
break;
118109

119-
case PD_CTRL_ACCEPT:
120-
break;
110+
case TCD_EVENT_RX_COMPLETE:
111+
// TODO process message here in ISR, move to thread later
112+
if (event.xfer_complete.result == XFER_RESULT_SUCCESS) {
113+
pd_header_t const* header = (pd_header_t const*) _rx_buf;
121114

122-
case PD_CTRL_REJECT:
123-
break;
115+
if (header->n_data_obj == 0) {
116+
parse_msg_control(event.rhport, header);
124117

125-
case PD_CTRL_PS_READY:
126-
break;
118+
}else {
119+
uint8_t const* p_end = _rx_buf + event.xfer_complete.xferred_bytes;
120+
uint8_t const * dobj = _rx_buf + sizeof(pd_header_t);
127121

128-
default: break;
129-
}
130-
} else {
131-
// data message
132-
switch (header->msg_type) {
133-
case PD_DATA_SOURCE_CAP: {
134-
// Examine source capability and select a suitable PDO (starting from 1 with safe5v)
135-
uint8_t obj_pos = 1;
136-
137-
for(size_t i=0; i<header->n_data_obj; i++) {
138-
TU_VERIFY(ptr < p_end);
139-
uint32_t const pdo = tu_le32toh(tu_unaligned_read32(ptr));
140-
141-
switch ((pdo >> 30) & 0x03ul) {
142-
case PD_PDO_TYPE_FIXED: {
143-
pd_pdo_fixed_t const* fixed = (pd_pdo_fixed_t const*) &pdo;
144-
TU_LOG3("[Fixed] %u mV %u mA\r\n", fixed->voltage_50mv*50, fixed->current_max_10ma*10);
145-
break;
146-
}
147-
148-
case PD_PDO_TYPE_BATTERY:
149-
break;
150-
151-
case PD_PDO_TYPE_VARIABLE:
152-
break;
153-
154-
case PD_PDO_TYPE_APDO:
155-
break;
122+
parse_msg_data(event.rhport, header, dobj, p_end);
156123
}
157-
158-
ptr += 4;
159124
}
160125

161-
// Send request with selected PDO position as response to Source Cap
162-
pd_rdo_fixed_variable_t rdo = {
163-
.current_extremum_10ma = 50, // max 500mA
164-
.current_operate_10ma = 30, // 300mA
165-
.reserved = 0,
166-
.epr_mode_capable = 0,
167-
.unchunked_ext_msg_support = 0,
168-
.no_usb_suspend = 0,
169-
.usb_comm_capable = 1,
170-
.capability_mismatch = 0,
171-
.give_back_flag = 0, // exteremum is max
172-
.object_position = obj_pos,
173-
};
174-
175-
pd_header_t const req_header = {
176-
.msg_type = PD_DATA_REQUEST,
177-
.data_role = PD_DATA_ROLE_UFP,
178-
.specs_rev = PD_REV_20,
179-
.power_role = PD_POWER_ROLE_SINK,
180-
.msg_id = 0,
181-
.n_data_obj = 1,
182-
.extended = 0,
183-
};
184-
185-
utcd_msg_send(rhport, &req_header, &rdo);
126+
// prepare for next message
127+
tcd_msg_receive(event.rhport, _rx_buf, sizeof(_rx_buf));
128+
break;
186129

130+
case TCD_EVENT_TX_COMPLETE:
187131
break;
188-
}
189132

190133
default: break;
191134
}
192135
}
136+
}
137+
138+
bool parse_msg_data(uint8_t rhport, pd_header_t const* header, uint8_t const* dobj, uint8_t const* p_end) {
139+
if (tuc_pd_data_received_cb) {
140+
tuc_pd_data_received_cb(rhport, header, dobj, p_end);
141+
}
142+
143+
return true;
144+
}
145+
146+
bool parse_msg_control(uint8_t rhport, pd_header_t const* header) {
147+
if (tuc_pd_control_received_cb) {
148+
tuc_pd_control_received_cb(rhport, header);
149+
}
193150

194151
return true;
195152
}
196153

154+
//--------------------------------------------------------------------+
155+
//
156+
//--------------------------------------------------------------------+
157+
158+
bool utcd_msg_send(uint8_t rhport, pd_header_t const* header, void const* data) {
159+
// copy header
160+
memcpy(_tx_buf, header, sizeof(pd_header_t));
161+
162+
// copy data objcet if available
163+
uint16_t const n_data_obj = header->n_data_obj;
164+
if (n_data_obj > 0) {
165+
memcpy(_tx_buf + sizeof(pd_header_t), data, n_data_obj * 4);
166+
}
167+
168+
return tcd_msg_send(rhport, _tx_buf, sizeof(pd_header_t) + n_data_obj * 4);
169+
}
170+
171+
bool tuc_msg_request(uint8_t rhport, void const* rdo) {
172+
pd_header_t const header = {
173+
.msg_type = PD_DATA_REQUEST,
174+
.data_role = PD_DATA_ROLE_UFP,
175+
.specs_rev = PD_REV_30,
176+
.power_role = PD_POWER_ROLE_SINK,
177+
.msg_id = 0,
178+
.n_data_obj = 1,
179+
.extended = 0,
180+
};
181+
182+
return utcd_msg_send(rhport, &header, rdo);
183+
}
184+
197185
void tcd_event_handler(tcd_event_t const * event, bool in_isr) {
198186
(void) in_isr;
199187
switch(event->event_id) {
200188
case TCD_EVENT_CC_CHANGED:
201189
if (event->cc_changed.cc_state[0] || event->cc_changed.cc_state[1]) {
202-
// Attach
190+
// Attach, start receiving
203191
tcd_msg_receive(event->rhport, _rx_buf, sizeof(_rx_buf));
204192
}else {
205193
// Detach
206194
}
207195
break;
208196

209-
case TCD_EVENT_RX_COMPLETE:
210-
// TODO process message here in ISR, move to thread later
211-
if (event->rx_complete.result == XFER_RESULT_SUCCESS) {
212-
parse_message(event->rhport, _rx_buf, event->rx_complete.xferred_bytes);
213-
}
214-
215-
// start new rx
216-
tcd_msg_receive(event->rhport, _rx_buf, sizeof(_rx_buf));
217-
break;
218-
219197
default: break;
220198
}
199+
200+
osal_queue_send(_utcd_q, event, in_isr);
221201
}
222202

223203
//--------------------------------------------------------------------+

0 commit comments

Comments
 (0)