Skip to content

Commit ff6eff9

Browse files
committed
Implement DTR+RTS hardware control handling
Adds compatibility with NXP Flash Magic for flashing NXP MCUs. Implements devanlai#3
1 parent 38fc2dc commit ff6eff9

File tree

5 files changed

+87
-3
lines changed

5 files changed

+87
-3
lines changed

src/DAP42.c

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,48 @@ static void on_dfu_request(void) {
7171
do_reset_to_dfu = true;
7272
}
7373

74+
static inline void set_target_state(bool reset, bool enter_bootloader) {
75+
/*
76+
* For transitioning from true/true to false/false, clear CTL first to ensure
77+
* the MCU does not enter the bootloader.
78+
*/
79+
PIN_CTL_OUT(enter_bootloader);
80+
PIN_nRESET_OUT(!reset);
81+
}
82+
83+
static bool do_deferred_set_target_state = false;
84+
static uint32_t set_target_state_timer_start;
85+
static bool set_target_state_reset;
86+
static bool set_target_state_enter_bootloader;
87+
static void on_cdc_set_control_line_state(bool dtr, bool rts) {
88+
/*
89+
* At least Linux and Windows set true/true by default when an app opens
90+
* the channel, so forwarding these values directly to set_target_state
91+
* would cause the target MCU to reset right away, even when one simply wants
92+
* to capture UART output without resetting the target. Therefore, this
93+
* combination must be ignored here.
94+
*
95+
* When NXP Flash Magic wants to reset the target, it first sets true/true,
96+
* followed by either true/false or false/true, followed by false/false.
97+
* Thus, the condition dtr != rts indicates it's time to reset the target.
98+
*/
99+
if (dtr != rts) {
100+
/* Reset now */
101+
set_target_state(true, true);
102+
103+
/* Defer setting the requested state */
104+
do_deferred_set_target_state = true;
105+
set_target_state_timer_start = get_ticks();
106+
set_target_state_reset = dtr;
107+
set_target_state_enter_bootloader = rts;
108+
}
109+
else if (!dtr) {
110+
/* Parameters are false/false */
111+
do_deferred_set_target_state = false;
112+
set_target_state(false, false);
113+
}
114+
}
115+
74116
int main(void) {
75117
if (DFU_AVAILABLE) {
76118
DFU_maybe_jump_to_bootloader();
@@ -109,7 +151,10 @@ int main(void) {
109151
DAP_app_setup(usbd_dev, &on_dfu_request);
110152

111153
if (CDC_AVAILABLE) {
112-
cdc_uart_app_setup(usbd_dev, &on_usb_activity, &on_usb_activity);
154+
cdc_uart_app_setup(usbd_dev,
155+
&on_cdc_set_control_line_state,
156+
&on_usb_activity,
157+
&on_usb_activity);
113158
cdc_uart_app_set_timeout(1);
114159
}
115160

@@ -175,6 +220,12 @@ int main(void) {
175220
} else {
176221
LED_ACTIVITY_OUT(0);
177222
}
223+
224+
bool timer_elapsed = (get_ticks() - set_target_state_timer_start) >= 25;
225+
if (do_deferred_set_target_state && timer_elapsed) {
226+
do_deferred_set_target_state = false;
227+
set_target_state(set_target_state_reset, set_target_state_enter_bootloader);
228+
}
178229
}
179230

180231
return 0;

src/USB/cdc.c

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,7 @@ static struct usb_cdc_line_coding current_line_coding = {
241241
};
242242

243243
void cdc_uart_app_reset(void);
244+
void cdc_uart_app_reset_buffer(void);
244245

245246
static bool cdc_uart_set_line_coding(const struct usb_cdc_line_coding* line_coding) {
246247
uint32_t databits;
@@ -281,7 +282,7 @@ static bool cdc_uart_set_line_coding(const struct usb_cdc_line_coding* line_codi
281282
}
282283

283284
// Reset the output packet buffer
284-
cdc_uart_app_reset();
285+
cdc_uart_app_reset_buffer();
285286

286287
console_reconfigure(line_coding->dwDTERate, databits, stopbits, parity);
287288
memcpy(&current_line_coding, (const void*)line_coding, sizeof(current_line_coding));
@@ -313,21 +314,29 @@ static uint32_t packet_timestamp = 0;
313314
static bool need_zlp = false;
314315

315316
void cdc_uart_app_reset(void) {
317+
if (cdc_set_control_line_state_callback) {
318+
cdc_set_control_line_state_callback(false, false);
319+
}
320+
cdc_uart_app_reset_buffer();
321+
}
322+
323+
void cdc_uart_app_reset_buffer(void) {
316324
packet_len = 0;
317325
packet_timestamp = get_ticks();
318326
need_zlp = false;
319327
cdc_clear_nak();
320328
}
321329

322330
void cdc_uart_app_setup(usbd_device* usbd_dev,
331+
SetControlLineStateFunction cdc_set_control_line_state_cb,
323332
GenericCallback cdc_tx_cb,
324333
GenericCallback cdc_rx_cb) {
325334
cdc_uart_tx_callback = cdc_tx_cb;
326335
cdc_uart_rx_callback = cdc_rx_cb;
327336

328337
cdc_setup(usbd_dev,
329338
&cdc_uart_on_host_tx,
330-
NULL,
339+
cdc_set_control_line_state_cb,
331340
&cdc_uart_set_line_coding, &cdc_uart_get_line_coding);
332341
cmp_usb_register_reset_callback(cdc_uart_app_reset);
333342
}

src/USB/cdc.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ extern void cdc_setup(usbd_device* usbd_dev,
3939
extern bool cdc_send_data(const uint8_t* data, size_t len);
4040

4141
extern void cdc_uart_app_setup(usbd_device* usbd_dev,
42+
SetControlLineStateFunction cdc_set_control_line_state_cb,
4243
GenericCallback cdc_tx_cb,
4344
GenericCallback cdc_rx_cb);
4445

src/stm32f042/DAP/CMSIS_DAP_hal.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,25 @@ static __inline void PIN_nRESET_OUT (uint32_t bit) {
254254
#endif
255255
}
256256

257+
/*
258+
CTL I/O pin: Set Output.
259+
Parameters
260+
bit target device enter bootloader pin status:
261+
0: do not enter bootloader.
262+
1: enter bootloader.
263+
*/
264+
static __inline void PIN_CTL_OUT (uint32_t bit) {
265+
#if defined(CTL_GPIO_PORT) && defined(CTL_GPIO_PIN)
266+
if (bit & 0x1) {
267+
GPIO_BRR(CTL_GPIO_PORT) = CTL_GPIO_PIN;
268+
} else {
269+
GPIO_BSRR(CTL_GPIO_PORT) = CTL_GPIO_PIN;
270+
}
271+
#else
272+
(void)bit;
273+
#endif
274+
}
275+
257276
/*
258277
Debug Unit: Set status of Connected LED.
259278
Parameters

src/stm32f103/DAP/CMSIS_DAP_hal.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,10 @@ static __inline void PIN_nRESET_OUT (uint32_t bit) {
189189
}
190190
}
191191

192+
static __inline void PIN_CTL_OUT (uint32_t bit) {
193+
(void)bit;
194+
}
195+
192196
static __inline void LED_CONNECTED_OUT (uint32_t bit) {
193197
if ((bit & 0x1) ^ LED_OPEN_DRAIN) {
194198
gpio_set(LED_CON_GPIO_PORT, LED_CON_GPIO_PIN);

0 commit comments

Comments
 (0)