В программаторе versaloon встроена реализация интерфейса UART. Если пины Rx и Tx в разъеме программатора не заняты, то его можно использовать даже вместе с другими интерфейсами. Таким образом в этой статье я покажу как совместить отладку по SWD и работу с UART. Вы сможете посылать байты по UART находясь в режиме отладки. Для этого подключим Rx и Tx отладочной платки к Tx и Rx программатора (серый и синий провод). Подробнее о подключении. При этом пины SWD остаются подключенными:

vsuartstm322.jpg

Для проверки я накидал примерчик, в котором контроллер ожидает байт по UART, и устанавливает состояние светодиодов в соответствии с двумя младшими битами этого байта. В ответ контроллер отправляет строку, с цветами включенных светодиодов. Вот исходный код:

#include "stm32f10x.h"
#define BAUDRATE 115200
uint8_t i = 0;
void uart_send_byte(uint8_t data) {
    while(!(USART1->SR & USART_SR_TC)); //Wait for transmit ready
    USART_SendData(USART1, data);
}
void uart_print(char* str){
    while(*str){
        uart_send_byte(*str);
        str++;
    }
}
void uart_println(char* str){
    uart_print(str);
    uart_print("\n\r");
}
int main(void) {
    // Enable clock of modules 
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB |
                            RCC_APB2Periph_GPIOA |
                            RCC_APB2Periph_AFIO  | 
                            RCC_APB2Periph_USART1, ENABLE);
    // disable JTAG for release LED PIN
    GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);
    // init led pins
    GPIO_InitTypeDef gpio_port;
    gpio_port.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5;
    gpio_port.GPIO_Mode = GPIO_Mode_Out_PP;  //Push Pull
    gpio_port.GPIO_Speed = GPIO_Speed_2MHz;
    GPIO_Init(GPIOB, &gpio_port);
    GPIOB->ODR = 0x0; //turn off leds
    // setup TX Pin
    gpio_port.GPIO_Pin = GPIO_Pin_9;
    gpio_port.GPIO_Speed = GPIO_Speed_50MHz;
    gpio_port.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_Init(GPIOA, &gpio_port);
    // setup RX Pin
    gpio_port.GPIO_Pin = GPIO_Pin_10;
    gpio_port.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    GPIO_Init(GPIOA, &gpio_port);
    // configure usart1
    USART_InitTypeDef uart_struct;
    uart_struct.USART_BaudRate            = BAUDRATE;
    uart_struct.USART_WordLength          = USART_WordLength_8b;
    uart_struct.USART_StopBits            = USART_StopBits_1;
    uart_struct.USART_Parity              = USART_Parity_No;
    uart_struct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    uart_struct.USART_Mode                = USART_Mode_Rx | USART_Mode_Tx;
    USART_Init(USART1, &uart_struct);
    USART_Cmd(USART1, ENABLE);
    // enable usart1 interrupt
    NVIC_InitTypeDef NVIC_InitStructure;
    NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
    USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
    NVIC_EnableIRQ(TIM2_IRQn);
    while(1) {}
}
void USART1_IRQHandler(void)
{
    //Receive Data register not empty interrupt
    if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)
    {
        USART_ClearITPendingBit(USART1, USART_IT_RXNE);
        uint8_t dr=USART_ReceiveData(USART1) - '0';
        uart_print("leds on: ");
        if (dr & 1) {
            GPIOB->ODR |= GPIO_Pin_4;
            uart_print("white ");
        } else {
            GPIOB->ODR &= ~GPIO_Pin_4;
        }
        if (dr & 2) {
            GPIOB->ODR |= GPIO_Pin_5;
            uart_print("blue");
        } else {
            GPIOB->ODR &= ~GPIO_Pin_5;
        }
        uart_println("");
    }
}

Ничего особенно в коде нету, его можно понять исследуя библиотеку и читая Reference Manual. Отдельно лишь прокомментирую строки 33-41, в которых настраиваются пины для модуля UART. В stm32 пины для периферийных модулей настраиваются вручную, причем нужно правильно выбрать режимы для них. Для пина TX я выбрал режим Push Pull, а для RX режим "плавающий вход". Откуда я узнал что нужно сделать именно так? Конечно можно логически понять, что принимающий пин должен быть настроен как вход, а передающий как выход, но лучше обратится к Reference Manual, в раздел 7.1.11 GPIO configurations for device peripherals. Table 22:

USARTSPINMODES(2).jpg

В строке 69 я отнимаю символ нуля от принятого байта, таким образом отправляя коды символов '0'(48), '1'(49), '2'(50) мы получим числа 0 (48-48), 1(49-48), 2(50-48) соответственно.

В строках 73 и 79 по uart-у обратно отправляется цвета включенных светодиодов. На PB.4 у меня припаян белый светодиод, а на PB.5 синий, по этому я использовал слова "white" и "blue".

Запуск

Для работы с com-портом в linux можно использовать простенькую терминальную программу screen.

Подключаем программатор и запускаем Debug. После запуска Resume (F8) перейдите в терминал и запустите:

sudo screen /dev/ttyACM0 115200

Если вы используете другие CDC устройства кроме versaloon, то ttyACM0 нужно заменить на тот, который занял versaloon.

После нажатия кнопок 1,2,3,4 на клавиатуре, в терминале должен появится вывод:

leds on: white 
leds on: blue
leds on: white blue
leds on:

Для выхода из screen нужно использовать комбинацию клавиш Ctrl+A,k,y.

В windows можно использовать какой-нибудь termite, с такими настройками:

COM3 замените на тот, который занял при подключении Versaloon. Результат:

Все статьи о versaloon ищите по тегу Versaloon.