STM32F103C8T6 Dev Board

Pinout

Install
- Open VSCode Extension Manager
- Search for official PlatformIO IDE extension
- Install PlatformIO IDE
- PIO Home -> New Project
- Board: BlackPill F103C8, Framework: libOpenCM3
Use
Blinky
- OpenCM3
- RTOS
#include <libopencm3/stm32/rcc.h>
#include <libopencm3/stm32/gpio.h>
// Setup
rcc_periph_clock_enable(RCC_GPIOC);
gpio_set_mode(GPIOC, GPIO_MODE_OUTPUT_2_MHZ,
GPIO_CNF_OUTPUT_PUSHPULL, GPIO13);
// Main Loop
while(1) {
gpio_clear(GPIOC, GPIO13);
for (int i = 0; i < 100000; i++) {
__asm__("nop");
}
gpio_set(GPIOC, GPIO13);
for (int i = 0; i < 100000; i++) {
__asm__("nop");
}
}
#include "FreeRTOS.h"
#include "task.h"
#include <libopencm3/stm32/rcc.h>
#include <libopencm3/stm32/gpio.h>
extern void vApplicationStackOverflowHook(xTaskHandle *pxTask, signed portCHAR *pcTaskName);
void vApplicationStackOverflowHook(
xTaskHandle *pxTask __attribute__((unused)),
signed portCHAR *pcTaskName __attribute__((unused))) {
for (;;);
}
static void task1(void *args __attribute__((unused))) {
for (;;) {
gpio_toggle(GPIOC, GPIO13);
vTaskDelay(pdMS_TO_TICKS(1000));
}
}
int main(void) {
// Use External crystal
rcc_clock_setup_in_hse_8mhz_out_72mhz();
rcc_periph_clock_enable(RCC_GPIOC);
gpio_set_mode(
GPIOC,
GPIO_MODE_OUTPUT_2_MHZ,
GPIO_CNF_OUTPUT_PUSHPULL,
GPIO13);
// Turn LED off
gpio_set(GPIOC, GPIO13);
xTaskCreate(task1, "LED", 100, NULL, 2, NULL);
vTaskStartScheduler();
for (;;);
return 0;
}
UART

- OpenCM3
- RTOS
#include <cstdlib>
#include <cstring>
#include <cstdarg>
#include <cstdio>
#include <libopencm3/stm32/usart.h>
// Setup
rcc_clock_setup_in_hse_8mhz_out_72mhz();
rcc_periph_clock_enable(RCC_GPIOA);
rcc_periph_clock_enable(RCC_USART1);
gpio_set_mode(GPIOA,
GPIO_MODE_OUTPUT_50_MHZ,
GPIO_CNF_OUTPUT_ALTFN_PUSHPULL,
GPIO_USART1_TX);
usart_set_baudrate(USART1, 115200);
usart_set_databits(USART1, 8);
usart_set_stopbits(USART1, USART_STOPBITS_1);
usart_set_mode(USART1, USART_MODE_TX);
usart_set_parity(USART1, USART_PARITY_NONE);
usart_set_flow_control(USART1, USART_FLOWCONTROL_NONE);
usart_enable(USART1);
// Send String
void puts(char *s) {
while (*s != '\0') {
usart_send_blocking(USART1, *s++);
}
}
void myprintf(const char *fmt, ...) {
static char buffer[256];
va_list args;
va_start(args, fmt);
vsnprintf(buffer, sizeof(buffer), fmt, args);
va_end(args);
puts(buffer);
}
myprintf("Hello World!\n");
See the output using minicom.
minicom -c -b 115200 -D /dev/ttyUSB0
static QueueHandle_t uart_txq;
void setup_uart() {
rcc_periph_clock_enable(RCC_GPIOA);
rcc_periph_clock_enable(RCC_USART1);
gpio_set_mode(GPIOA,
GPIO_MODE_OUTPUT_50_MHZ,
GPIO_CNF_OUTPUT_ALTFN_PUSHPULL,
GPIO_USART1_TX);
usart_set_baudrate(USART1, 38400);
usart_set_databits(USART1, 8);
usart_set_stopbits(USART1, USART_STOPBITS_1);
usart_set_mode(USART1, USART_MODE_TX);
usart_set_parity(USART1, USART_PARITY_NONE);
usart_set_flow_control(USART1, USART_FLOWCONTROL_NONE);
usart_enable(USART1);
uart_txq = xQueueCreate(256, sizeof(char));
}
void uart_publisher_task(void *args __attribute__((unused))) {
int c = '0' - 1;
for (;;) {
vTaskDelay(pdMS_TO_TICKS(1000));
usart_puts("Hello World!\n\r");
}
}
void uart_sender_task(void *args __attribute__((unused))) {
char c;
for (;;) {
if (xQueueReceive(uart_txq, &c, 500) == pdPASS) {
// Transmit data buffer empty?
while(!usart_get_flag(USART1, USART_SR_TXE)) {
taskYIELD();
}
usart_send(USART1, c);
}
}
}
void usart_puts(const char* s) {
for(;*s;++s) {
xQueueSend(uart_txq, s, portMAX_DELAY);
}
}
See the output using minicom.
minicom -c -b 115200 -D /dev/ttyUSB0
GPIO Input
#include <libopencm3/stm32/rcc.h>
#include <libopencm3/stm32/gpio.h>
// [...]
rcc_periph_clock_enable(RCC_GPIOC);
gpio_set_mode(
GPIOC,
GPIO_MODE_INPUT,
GPIO_CNF_INPUT_ANALOG, /* GPIO_CNF_INPUT_FLOAT | GPIO_INPUT_PULL_UPDOWN */
GPIO13
);
// [...]
uint16_t gpio_get(uint32_t gpioport, uint16_t gpios);
uint16_t gpio_port_read(uint32_t gpioport);
GPIO Output
#include <libopencm3/stm32/rcc.h>
#include <libopencm3/stm32/gpio.h>
// [...]
rcc_periph_clock_enable(RCC_GPIOC);
gpio_set_mode(
GPIOC,
GPIO_MODE_OUTPUT_2_MHZ, /* GPIO_MODE_OUTPUT_10_MHZ | GPIO_MODE_OUTPUT_50_MHZ */
GPIO_CNF_OUTPUT_PUSHPULL, /* GPIO_CNF_OUTPUT_OPENDRAIN */
GPIO13
);
// [...]
void gpio_set(uint32_t gpioport, uint16_t gpios);
void gpio_clear(uint32_t gpioport, uint16_t gpios);
void gpio_toggle(uint32_t gpioport, uint16_t gpios);
void gpio_port_write(uint32_t gpioport, uint16_t data);
I2C
#include <libopencm3/stm32/i2c.h>
i2c_peripheral_disable(I2C1);
i2c_reset(I2C1);
I2C_CR1(I2C1) &= ~I2C_CR1_STOP;
i2c_set_standard_mode(I2C1); // 100 khz
i2c_set_clock_frequency(I2C1, I2C_CR2_FREQ_36MHZ);
i2c_set_trise(I2C1, 36);
i2c_set_dutycycle(I2C1, I2C_CCR_DUTY_DIV2);
i2c_set_ccr(I2C1, 180);
i2c_set_own_7bit_slave_address(I2C1, 0x23);
i2c_peripheral_enable(I2C1);
uint8_t SLAVE_ADDRESS = 0x1E;
// Write
uint8_t write[2] {0x00, 0x70};
i2c_transfer7(I2C1, SLAVE_ADDRESS, write, 2, nullptr, 0);
// Write and read
uint8_t write[1] {0x03};
uint8_t read[6]{};
i2c_transfer7(I2C1, SLAVE_ADDRESS, write, 1, read, 6);
SD Card

Encoder
Setup

#include <libopencm3/stm32/rcc.h>
#include <libopencm3/stm32/timer.h>
rcc_periph_clock_enable(RCC_TIM3);
timer_slave_set_mode(TIM3, 0x3); // encoder
timer_ic_set_input(TIM3, TIM_IC1, TIM_IC_IN_TI1);
timer_ic_set_input(TIM3, TIM_IC2, TIM_IC_IN_TI2);
timer_enable_counter(TIM3);
Get Counter Value
uint32_t motor_pos = timer_get_counter(TIM3);