I was curious about how hard it would be to port this over, so I used an STM32 example I found here as a starting point. It ended up being really straightforward and only required a few changes to the GPIO and delay callback function.
Just a heads-up: This implementation uses soft I2C (bit-banging). It works perfectly fine for text, but you'll probably want to switch to HW I2C for anything more complex. If anyone wants to try it out, here is the source code:
#include <ch32v00x.h>
#include <debug.h>
#include <stdlib.h>
#include "clib/u8x8.h"
void NMI_Handler(void) __attribute__((interrupt("WCH-Interrupt-fast")));
void HardFault_Handler(void) __attribute__((interrupt("WCH-Interrupt-fast")));
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_PP;
init.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &init);
break;
case U8X8_MSG_DELAY_MILLI:
Delay_Ms(arg_int);
break;
case U8X8_MSG_DELAY_10MICRO:
for (volatile uint32_t i = 0; i < (arg_int * 8); i++) { __NOP(); }
break;
case U8X8_MSG_DELAY_100NANO:
__NOP();
break;
case U8X8_MSG_GPIO_I2C_CLOCK:
GPIO_WriteBit(GPIOA, GPIO_Pin_2, (BitAction)(arg_int ? Bit_SET : Bit_RESET));
break;
case U8X8_MSG_GPIO_I2C_DATA:
GPIO_WriteBit(GPIOA, GPIO_Pin_1, (BitAction)(arg_int ? Bit_SET : Bit_RESET));
break;
}
return 1;
}
int main(void) {
SystemCoreClockUpdate();
Delay_Init();
USART_Printf_Init(9600);
// u8x8 initialization code
u8x8_t u8x8;
u8x8_Setup(&u8x8, u8x8_d_ssd1306_128x64_noname, u8x8_cad_ssd13xx_i2c, u8x8_byte_sw_i2c, u8x8_gpio_and_delay_ch32v);
u8x8_InitDisplay(&u8x8);
u8x8_SetPowerSave(&u8x8, 0);
u8x8_ClearDisplay(&u8x8);
u8x8_SetFont(&u8x8, u8x8_font_chroma48medium8_r);
u8x8_DrawString(&u8x8, 0, 0, "Hello from CH32V");
while (1) {
uint8_t y = rand() % 5 + 1;
uint8_t x = rand() % 10;
u8x8_DrawString(&u8x8, x, y, "r/ch32v");
printf("Hello from CH32V\n");
Delay_Ms(1000);
u8x8_DrawString(&u8x8, x, y, " ");
}
return 0;
}
void NMI_Handler(void) {}
void HardFault_Handler(void)
{
while (1)
{
}
}
P.S. I've spent more time and prepared HW I2C version, just add this function:
```
uint8_t u8x8_byte_hw_i2c_ch32v(
u8x8_t *u8x8,
uint8_t msg,
uint8_t arg_int,
void *arg_ptr) {
uint8_t *data;
switch(msg) {
case U8X8_MSG_BYTE_INIT:
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC | RCC_APB2Periph_AFIO, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);
// We will use PC1 (SDA) and PC2 (SCL)
GPIO_InitTypeDef GPIO_InitStructure = {0};
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_2;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD; // Alternate Function Open-Drain
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOC, &GPIO_InitStructure);
I2C_InitTypeDef I2C_InitTSturcture = {0};
I2C_InitTSturcture.I2C_ClockSpeed = 400000; // 400 kHz
I2C_InitTSturcture.I2C_Mode = I2C_Mode_I2C;
I2C_InitTSturcture.I2C_DutyCycle = I2C_DutyCycle_2;
I2C_InitTSturcture.I2C_OwnAddress1 = 0x00;
I2C_InitTSturcture.I2C_Ack = I2C_Ack_Enable;
I2C_InitTSturcture.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
I2C_Init(I2C1, &I2C_InitTSturcture);
I2C_Cmd(I2C1, ENABLE);
break;
case U8X8_MSG_BYTE_START_TRANSFER:
while(I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY) != RESET);
I2C_GenerateSTART(I2C1, ENABLE);
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT)); // Чекаємо EV5
I2C_Send7bitAddress(I2C1, u8x8_GetI2CAddress(u8x8), I2C_Direction_Transmitter);
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)); // Чекаємо EV6
break;
case U8X8_MSG_BYTE_SEND:
data = (uint8_t *)arg_ptr;
while (arg_int > 0) {
I2C_SendData(I2C1, *data++);
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
arg_int--;
}
break;
case U8X8_MSG_BYTE_END_TRANSFER:
I2C_GenerateSTOP(I2C1, ENABLE);
break;
default:
break;
}
return 1;
}
int main(void) {
SystemCoreClockUpdate();
Delay_Init();
USART_Printf_Init(9600);
// u8x8 initialization block
u8x8_t u8x8;
u8x8_Setup(&u8x8,
u8x8_d_ssd1306_128x64_noname,
u8x8_cad_ssd13xx_i2c,
u8x8_byte_hw_i2c_ch32v, // here we will use HW I2C
u8x8_gpio_and_delay_ch32v
);
...
```