Posts

Understanding Rotary Encoders: Teardown, Oscilloscope Signals, and C Code for CH32V

Image
A Bit of Theory An encoder is an electromechanical component that helps electronics determine the speed and direction of a shaft’s rotation, and in some cases, accurately register its angular position. Therefore, if your project involves moving parts and you need to track their rotation or angle, you cannot do without this sensor. We don’t need to look at complex industrial machinery for examples - we encounter encoders constantly in everyday life. A computer mouse wheel, a car stereo volume knob, or a washing machine mode selector - all of these are convenient physical interfaces for interacting with technology. The simplest encoders can only register movement. In the case of a mouse, we don’t care about the exact position of the wheel - we just scroll it up or down to scroll the page. But for some processes, the exact position is crucial, which is where more complex absolute encoders are used. By design, these sensors are based on various physical principles. Inside, there migh...

Available WCH-Link Programmers

Image
Wch-Link V1 When I first paid attention to CH32V microcontrollers on AliExpress, I immediately bought a few different boards: a couple with the CH32V003 and a more powerful one with the CH32V307. However, a logical question immediately arose: how do I program them? My usual ST-Link definitely wouldn’t work for this architecture. So, I just found the first available programmer with the WCH label from the same seller and added it to my order. It turned out to be the WCH-Link v1, based on the CH549G chip. Its pros: Relatively low price: during sales, you can find them starting at $2. Versatility: it supports both RISC-V based WCH microcontrollers and ARM-compatible chips in DAP mode (although I haven’t tested the latter in practice yet). Built-in USB-UART: this is incredibly convenient for debugging, and it’s a feature I often missed in the standard ST-Link. However, there were also downsides that came as an unpleasant surprise. The main drawback is that it does not program th...

Bit-bang vs. Hardware I2C: Running U8x8 on CH32V003

Image
In a project with an OLED display and an STM32F103 microcontroller, a question arose: can we make this cheaper? What if we use the CH32V003? We don’t need many pins, so the SOP16 package will be enough. The main question is how it will work with the SSD1306 OLED. Let’s find out. As I wrote earlier, U8x8 should be easy to port and can work with software I2C (bit-bang). Porting the code from CMSIS went very quickly — a couple of cups of coffee, and I got the example working. Here is the code for the u8x8_gpio_and_delay_ch32v function: uint8_t u8x8_gpio_and_delay_ch32v(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr) { switch(msg) { case U8X8_MSG_GPIO_AND_DELAY_INIT: RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); GPIO_InitTypeDef init = {0}; init.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_2; init.GPIO_Mode = GPIO_Mode_Out_OD; init.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &init); ...

How to Use the U8x8 Library on STM32 with Pure CMSIS

Image
For Arduino, there is a quite popular library for monochrome displays - U8g2 . This library has two independent subsystems: U8g2 — for drawing various graphical elements, and u8x8 — strictly for text. And today I need to run u8x8 on an STM32 without Arduino, in a pure CMSIS project. I have a PlatformIO project, so as a first step, I am adding the U8g2 dependency to it: [env:genericSTM32F103C8] platform = ststm32 board = genericSTM32F103C8 framework = cmsis upload_protocol = cmsis-dap debug_tool = cmsis-dap lib_deps = olikraus/U8g2 lib_compat_mode = off The lib_compat_mode = off parameter disables the compatibility check; otherwise, PlatformIO won’t add the library to the build since it is intended for the Arduino framework. Our initial code is almost empty for now, we are only initializing a timer. We will run on the internal RC oscillator at 8 MHz. #include "stm32f1xx.h" volatile uint32_t ms_ticks = 0 ; extern "C" void SysTick_Handler ( void )...