きわめてレアなトラブルだとは思いますが、解決したので記録しておきます。
ピン機能の変更
Bluepill に載っているマイコン STM32F103 では、フラッシュメモリの書き込みやデバッグに使う JTAG/SMD ピンを、下記のコードで GPIO(PA13, PA14) に変更できます (RM0008 リファレンスマニュアル 8.3.5 「JTAG/SWD オルタネート機能の再配置」参照)。
main.c
RCC->APB2ENR |= (1 << 0); // AF クロック有効化
AFIO->MAPR=0x04000000| (AFIO->MAPR & 0x00ffffff); // SW 無効化
発生したトラブルと回避方法
PA13, PA14 を両方出力ピンにして、そこに DMA を使ってパルスを出力すると、突然リセットがかかるという異常な動作が起こりました。本来は発生しないはずですが、STM32F103 がクローン品だと発生する現象のようです。
あらかじめ RM0008 リファレンスマニュアル 30.3.1 「JTAG-DP または SW-DP の選択メカニズム」に沿って、モードを JTAG から SW-DP に切り替えておくことで、この問題を回避して、PA13, PA14 を両方出力ピンにできました。
STM32CubeMX で PA13 と PA14 を出力ポートに設定し、MX_GPIO_Init() が呼ばれた後に、下記のコードを挿入すれば OK です。
main.c
RCC->APB2ENR |= (1 << 0); // AF クロック有効化
AFIO->MAPR=0x04000000| (AFIO->MAPR & 0x00ffffff); // SW 無効化
// SWDIO:PA13, SWCLK:PA14
#define SWDIO_H do { GPIOA->BSRR = (1<<(13+0)); } while(0)
#define SWDIO_L do { GPIOA->BSRR = (1<<(13+16)); } while(0)
#define SWCLK_H do { GPIOA->BSRR = (1<<(14+0)); } while(0)
#define SWCLK_L do { GPIOA->BSRR = (1<<(14+16)); } while(0)
int i;
SWDIO_H;
for (i=0; i<60; i++) {SWCLK_H; SWCLK_L;}
// SWCLK のアップエッジで 0111 1001 1110 0111 を出力
SWDIO_L; SWCLK_H; SWCLK_L; // 0
SWDIO_H; SWCLK_H; SWCLK_L; // 1
SWDIO_H; SWCLK_H; SWCLK_L; // 1
SWDIO_H; SWCLK_H; SWCLK_L; // 1
SWDIO_H; SWCLK_H; SWCLK_L; // 1
SWDIO_L; SWCLK_H; SWCLK_L; // 0
SWDIO_L; SWCLK_H; SWCLK_L; // 0
SWDIO_H; SWCLK_H; SWCLK_L; // 1
SWDIO_H; SWCLK_H; SWCLK_L; // 1
SWDIO_H; SWCLK_H; SWCLK_L; // 1
SWDIO_H; SWCLK_H; SWCLK_L; // 1
SWDIO_L; SWCLK_H; SWCLK_L; // 0
SWDIO_L; SWCLK_H; SWCLK_L; // 0
SWDIO_H; SWCLK_H; SWCLK_L; // 1
SWDIO_H; SWCLK_H; SWCLK_L; // 1
SWDIO_H; SWCLK_H; SWCLK_L; // 1
SWDIO_H;
for (i=0; i<60; i++) {SWCLK_H; SWCLK_L;}