Initial RTOS support with LED driver.

Signed-off-by: Yilin Sun <imi415@imi.moe>
This commit is contained in:
Yilin Sun 2023-10-17 09:40:07 +08:00
parent 1cc88f3d5e
commit 5e568857b2
Signed by: imi415
GPG Key ID: 17F01E106F9F5E0A
12 changed files with 422 additions and 37 deletions

3
.gitmodules vendored
View File

@ -1,3 +1,6 @@
[submodule "SDK"]
path = SDK
url = https://git.minori.work/Embedded_SDK/WCH_CH32X035.git
[submodule "lib/freertos"]
path = lib/freertos
url = https://github.com/imi415/FreeRTOS-Kernel.git

View File

@ -1,12 +1,13 @@
cmake_minimum_required(VERSION 3.10)
project(ch32x035_template)
project(ch32x035_freertos)
enable_language(CXX)
enable_language(ASM)
# Different linker scripts
set(TARGET_LDSCRIPT_FLASH "${CMAKE_SOURCE_DIR}/SDK/Ld/Link.ld")
set(TARGET_LDSCRIPT_FLASH "${CMAKE_SOURCE_DIR}/SDK/Ld/CH32X035_FLASH.ld")
set(TARGET_LDSCRIPT_PIOC_FLASH "${CMAKE_SOURCE_DIR}/SDK/Ld/CH32X035_PIOC_FLASH.ld")
set(TARGET_SOURCES
"SDK/Core/core_riscv.c"
@ -30,11 +31,14 @@ set(TARGET_SOURCES
"SDK/Peripheral/src/ch32x035_wwdg.c"
"SDK/Startup/startup_ch32x035.S"
"board/ch32x035_it.c"
"board/freertos_helpers.c"
"board/system_ch32x035.c"
"src/app_led1w.c"
"src/main.c"
)
set(TARGET_C_DEFINES
"DEBUG_UART=1"
)
set(TARGET_C_INCLUDES
@ -47,6 +51,7 @@ set(TARGET_C_INCLUDES
# Shared libraries linked with application
set(TARGET_LIBS
"freertos_kernel"
"c"
"m"
"nosys"
@ -74,6 +79,16 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -fno-common -fno-builtin -f
set(CMAKE_ASM_FLAGS "${CMAKE_C_FLAGS} -x assembler-with-cpp")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-sections")
# FreeRTOS
set(FREERTOS_PORT "GCC_RISC_V_WCH_RISC_V4C" CACHE STRING "")
set(FREERTOS_HEAP "4" CACHE STRING "")
add_library(freertos_config INTERFACE)
target_include_directories(freertos_config SYSTEM INTERFACE include)
add_subdirectory(lib/freertos)
# Shared sources, includes and definitions
add_compile_definitions(${TARGET_C_DEFINES})
include_directories(${TARGET_C_INCLUDES})
@ -84,9 +99,6 @@ link_libraries(${TARGET_LIBS})
# Create ELF
add_executable("${CMAKE_PROJECT_NAME}_FLASH.elf" ${TARGET_SOURCES})
target_compile_definitions("${CMAKE_PROJECT_NAME}_FLASH.elf"
PRIVATE ${TARGET_C_DEFINES_XIP}
)
target_link_options("${CMAKE_PROJECT_NAME}_FLASH.elf"
PRIVATE "-T${TARGET_LDSCRIPT_FLASH}"
PRIVATE "-Wl,--Map=${CMAKE_PROJECT_NAME}_FLASH.map"
@ -104,3 +116,23 @@ if(DEFINED TARGET_TOOLCHAIN_SIZE)
COMMAND ${TARGET_TOOLCHAIN_SIZE} "${CMAKE_PROJECT_NAME}_FLASH.elf"
)
endif()
# Create ELF
add_executable("${CMAKE_PROJECT_NAME}_PIOC_FLASH.elf" ${TARGET_SOURCES})
target_link_options("${CMAKE_PROJECT_NAME}_PIOC_FLASH.elf"
PRIVATE "-T${TARGET_LDSCRIPT_PIOC_FLASH}"
PRIVATE "-Wl,--Map=${CMAKE_PROJECT_NAME}_PIOC_FLASH.map"
)
set_property(TARGET "${CMAKE_PROJECT_NAME}_PIOC_FLASH.elf" APPEND
PROPERTY ADDITIONAL_CLEAN_FILES "${CMAKE_PROJECT_NAME}_PIOC_FLASH.map"
)
add_custom_command(OUTPUT "${CMAKE_PROJECT_NAME}_PIOC_FLASH.hex"
COMMAND ${CMAKE_OBJCOPY} "-O" "ihex" "${CMAKE_PROJECT_NAME}_PIOC_FLASH.elf" "${CMAKE_PROJECT_NAME}_PIOC_FLASH.hex"
DEPENDS "${CMAKE_PROJECT_NAME}_PIOC_FLASH.elf"
)
add_custom_target("${CMAKE_PROJECT_NAME}_PIOC_FLASH_HEX" DEPENDS "${CMAKE_PROJECT_NAME}_PIOC_FLASH.hex")
if(DEFINED TARGET_TOOLCHAIN_SIZE)
add_custom_command(TARGET "${CMAKE_PROJECT_NAME}_PIOC_FLASH.elf" POST_BUILD
COMMAND ${TARGET_TOOLCHAIN_SIZE} "${CMAKE_PROJECT_NAME}_PIOC_FLASH.elf"
)
endif()

1
SDK Submodule

@ -0,0 +1 @@
Subproject commit 49754ad11b59d5982e8e3368e4b5ba0c278295db

View File

@ -1,37 +1,38 @@
/********************************** (C) COPYRIGHT *******************************
* File Name : ch32x035_it.c
* Author : WCH
* Version : V1.0.0
* Date : 2023/04/06
* Description : Main Interrupt Service Routines.
*********************************************************************************
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
* Attention: This software (modified or not) and binary are used for
* microcontroller manufactured by Nanjing Qinheng Microelectronics.
*******************************************************************************/
#include "ch32x035_it.h"
void NMI_Handler(void) __attribute__((interrupt));
void HardFault_Handler(void) __attribute__((interrupt));
#define __IRQ __attribute__((interrupt(), used))
#define __IRQ_WEAK __attribute__((interrupt(), weak))
#define __IRQ_NAKED __attribute__((naked, used))
/*********************************************************************
* @fn NMI_Handler
*
* @brief This function handles NMI exception.
*
* @return none
*/
void NMI_Handler(void) {
}
void app_led1w_irq_handler(void);
/*********************************************************************
* @fn HardFault_Handler
*
* @brief This function handles Hard Fault exception.
*
* @return none
*/
void HardFault_Handler(void) {
while (1) {
__IRQ void NMI_Handler(void) {
for (;;) {
__WFI();
}
}
__IRQ void HardFault_Handler(void) {
for (;;) {
__WFI();
}
}
__IRQ_NAKED void Ecall_M_Mode_Handler(void) {
asm volatile("j freertos_risc_v_exception_handler");
}
__IRQ_NAKED void SysTick_Handler(void) {
asm volatile(
"addi sp, sp, -4\n" /* Push */
"sw t0, 4(sp)\n" /* Save t0 on stack */
"li t0, 0xE000F004\n" /* SysTick->SR */
"sw zero, 0(t0)\n" /* Write 0 to clear */
"lw t0, 4(sp)\n" /* Restore t0 from stack */
"addi sp, sp, 4\n" /* Pop */
"j freertos_risc_v_mtimer_interrupt_handler");
}
__IRQ void DMA1_Channel3_IRQHandler(void) {
app_led1w_irq_handler();
}

25
board/freertos_helpers.c Normal file
View File

@ -0,0 +1,25 @@
#include "FreeRTOS.h"
#include "task.h"
/* Device */
#include "ch32x035.h"
#include "system_ch32x035.h"
/**
* @brief Initialize SysTick interrupt.
*
*/
void vPortSetupTimerInterrupt(void) {
/* Configure SysTick and interrupts. */
SysTick->SR = 0UL;
SysTick->CTLR = 0UL;
SysTick->CNT = 0UL;
NVIC_EnableIRQ(SysTicK_IRQn);
SysTick->CMP = (uint64_t)((SystemCoreClock / (configTICK_RATE_HZ * 8)) - 1);
SysTick->CTLR = 0x1A; /* COUNTDOWN | AUTO RELOAD | HCLK/8 | INT */
SysTick->CTLR |= 0x20; /* INIT */
SysTick->CTLR |= 0x01; /* EN */
}

89
include/FreeRTOSConfig.h Normal file
View File

@ -0,0 +1,89 @@
#ifndef FREERTOS_CONFIG_H
#define FREERTOS_CONFIG_H
/* RISC-V related configuration */
#define configMTIME_BASE_ADDRESS 0
#define configMTIMECMP_BASE_ADDRESS 0
/* General configuration */
#define configUSE_PREEMPTION 1
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 0
#define configUSE_TICKLESS_IDLE 0
#define configCPU_CLOCK_HZ 48000000 /* This is literally not used, keep it to make port.c happy. */
#define configTICK_RATE_HZ 1000
#define configMAX_PRIORITIES 8
#define configMINIMAL_STACK_SIZE 128
#define configMAX_TASK_NAME_LEN 16
#define configUSE_16_BIT_TICKS 0
#define configIDLE_SHOULD_YIELD 1
#define configUSE_TASK_NOTIFICATIONS 1
#define configTASK_NOTIFICATION_ARRAY_ENTRIES 3
#define configUSE_MUTEXES 0
#define configUSE_RECURSIVE_MUTEXES 0
#define configUSE_COUNTING_SEMAPHORES 0
#define configUSE_ALTERNATIVE_API 0 /* Deprecated! */
#define configQUEUE_REGISTRY_SIZE 10
#define configUSE_QUEUE_SETS 0
#define configUSE_TIME_SLICING 0
#define configUSE_NEWLIB_REENTRANT 1
#define configENABLE_BACKWARD_COMPATIBILITY 0
#define configNUM_THREAD_LOCAL_STORAGE_POINTERS 5
#define configSTACK_DEPTH_TYPE uint16_t
#define configMESSAGE_BUFFER_LENGTH_TYPE size_t
/* Memory allocation related definitions. */
#define configSUPPORT_STATIC_ALLOCATION 0
#define configSUPPORT_DYNAMIC_ALLOCATION 1
#define configTOTAL_HEAP_SIZE 10240
#define configAPPLICATION_ALLOCATED_HEAP 0
#define configSTACK_ALLOCATION_FROM_SEPARATE_HEAP 0
/* Hook function related definitions. */
#define configUSE_IDLE_HOOK 0
#define configUSE_TICK_HOOK 0
#define configCHECK_FOR_STACK_OVERFLOW 0
#define configUSE_MALLOC_FAILED_HOOK 0
#define configUSE_DAEMON_TASK_STARTUP_HOOK 0
/* Run time and task stats gathering related definitions. */
#define configGENERATE_RUN_TIME_STATS 0
#define configUSE_TRACE_FACILITY 0
#define configUSE_STATS_FORMATTING_FUNCTIONS 0
/* Co-routine related definitions. */
#define configUSE_CO_ROUTINES 0
#define configMAX_CO_ROUTINE_PRIORITIES 1
/* Software timer related definitions. */
#define configUSE_TIMERS 1
#define configTIMER_TASK_PRIORITY 3
#define configTIMER_QUEUE_LENGTH 10
#define configTIMER_TASK_STACK_DEPTH configMINIMAL_STACK_SIZE
/* Define to trap errors during development. */
#define configASSERT( x ) if( ( x ) == 0 ) for(;;) { }
/* Optional functions - most linkers will remove unused functions anyway. */
#define INCLUDE_vTaskPrioritySet 1
#define INCLUDE_uxTaskPriorityGet 1
#define INCLUDE_vTaskDelete 1
#define INCLUDE_vTaskSuspend 1
#define INCLUDE_xResumeFromISR 1
#define INCLUDE_vTaskDelayUntil 1
#define INCLUDE_vTaskDelay 1
#define INCLUDE_xTaskGetSchedulerState 1
#define INCLUDE_xTaskGetCurrentTaskHandle 1
#define INCLUDE_uxTaskGetStackHighWaterMark 0
#define INCLUDE_xTaskGetIdleTaskHandle 0
#define INCLUDE_eTaskGetState 0
#define INCLUDE_xEventGroupSetBitFromISR 1
#define INCLUDE_xTimerPendFunctionCall 0
#define INCLUDE_xTaskAbortDelay 0
#define INCLUDE_xTaskGetHandle 0
#define INCLUDE_xTaskResumeFromISR 1
#define __freertos_irq_stack_top __stack_top
/* A header file that defines trace macro can be included here. */
#endif /* FREERTOS_CONFIG_H */

9
include/app_led1w.h Normal file
View File

@ -0,0 +1,9 @@
#ifndef APP_LED1W_H
#define APP_LED1W_H
#include <stdint.h>
void app_led1w_init(void);
int app_led1w_write(uint8_t *data, uint16_t led_count);
#endif // APP_LED1W_H

1
lib/freertos Submodule

@ -0,0 +1 @@
Subproject commit a47bffbfc841f99dfbab1fac46a9d021ec9dbb0c

View File

@ -11,7 +11,7 @@ set(TARGET_TOOLCHAIN_SIZE riscv64-elf-size)
set(CMAKE_C_FLAGS_INIT "-march=rv32imac_zicsr -mabi=ilp32")
set(CMAKE_CXX_FLAGS_INIT "-march=rv32imac_zicsr -mabi=ilp32")
set(CMAKE_EXE_LINKER_FLAGS_INIT "-specs=nano.specs -specs=nosys.specs -nostartfiles -Wl,--print-memory-usage -Wl,--no-warn-rwx-segments")
set(CMAKE_EXE_LINKER_FLAGS_INIT "-march=rv32imac -mabi=ilp32 -specs=nano.specs -specs=nosys.specs -nostartfiles -Wl,--print-memory-usage -Wl,--no-warn-rwx-segments")
# Make CMake happy about those compilers
set(CMAKE_TRY_COMPILE_TARGET_TYPE "STATIC_LIBRARY")

View File

@ -0,0 +1,17 @@
# Poor old Windows...
if(WIN32)
set(CMAKE_SYSTEM_NAME "Generic")
endif()
set(CMAKE_C_COMPILER riscv64-multilib-elf-gcc)
set(CMAKE_CXX_COMPILER riscv64-multilib-elf-g++)
# Optionally set size binary name, for elf section size reporting.
set(TARGET_TOOLCHAIN_SIZE riscv64-multilib-elf-size)
set(CMAKE_C_FLAGS_INIT "-march=rv32imac_zicsr -mabi=ilp32")
set(CMAKE_CXX_FLAGS_INIT "-march=rv32imac_zicsr -mabi=ilp32")
set(CMAKE_EXE_LINKER_FLAGS_INIT "-specs=nano.specs -specs=nosys.specs -nostartfiles -Wl,--print-memory-usage -Wl,--no-warn-rwx-segments")
# Make CMake happy about those compilers
set(CMAKE_TRY_COMPILE_TARGET_TYPE "STATIC_LIBRARY")

122
src/app_led1w.c Normal file
View File

@ -0,0 +1,122 @@
#include <stdint.h>
/* SDK */
#include "ch32x035.h"
#include "ch32x035_dma.h"
#include "ch32x035_gpio.h"
#include "ch32x035_spi.h"
/* Private */
#include "app_led1w.h"
#define APP_LED1W_MAXIMUM_LEDS 64
#define APP_LED1W_ZERO_PADDING 32 /* Additional padding for a RESET condition (50uS) */
#define APP_LED1W_SPI_0B (0x08U) /* 4'b1000 */
#define APP_LED1W_SPI_1B (0x0EU) /* 4'b1110 */
/* SPI buffer to store waveform data */
static uint8_t s_led1w_spi_buf[APP_LED1W_MAXIMUM_LEDS * 3 * 8 / 2 + APP_LED1W_ZERO_PADDING];
static void app_led1w_encode(const uint8_t *data, uint16_t len);
void app_led1w_init(void) {
/* Enable DMA and SPI clocks */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
/* Initialize SPI peripheral */
SPI_InitTypeDef spi_init;
/*
* 48MHz / 16 = 3MHz
* Timing:
* T0H: 334ns
* T0L: 1002ns
* T1H: 1002ns
* T1L: 334ns
*/
spi_init.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_16;
spi_init.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
spi_init.SPI_Mode = SPI_Mode_Master;
spi_init.SPI_CPOL = SPI_CPOL_Low;
spi_init.SPI_CPHA = SPI_CPHA_1Edge;
spi_init.SPI_NSS = SPI_NSS_Soft;
spi_init.SPI_FirstBit = SPI_FirstBit_MSB;
spi_init.SPI_DataSize = SPI_DataSize_8b;
SPI_Init(SPI1, &spi_init);
GPIO_InitTypeDef gpio_init;
gpio_init.GPIO_Pin = GPIO_Pin_7;
gpio_init.GPIO_Mode = GPIO_Mode_AF_PP;
gpio_init.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &gpio_init);
}
int app_led1w_write(uint8_t *data, uint16_t led_count) {
uint16_t byte_count = led_count * 3 * 8 / 2;
if ((byte_count + APP_LED1W_ZERO_PADDING) > sizeof(s_led1w_spi_buf)) {
return -1;
}
app_led1w_encode(data, led_count * 3);
/* Initialize DMA peripheral */
DMA_InitTypeDef dma_init;
dma_init.DMA_PeripheralBaseAddr = (uint32_t)&SPI1->DATAR;
dma_init.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
dma_init.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
dma_init.DMA_MemoryBaseAddr = (uint32_t)s_led1w_spi_buf;
dma_init.DMA_MemoryInc = DMA_MemoryInc_Enable;
dma_init.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
dma_init.DMA_DIR = DMA_DIR_PeripheralDST;
dma_init.DMA_Mode = DMA_Mode_Normal;
dma_init.DMA_Priority = DMA_Priority_Medium;
dma_init.DMA_M2M = DMA_M2M_Disable;
dma_init.DMA_BufferSize = byte_count + APP_LED1W_ZERO_PADDING;
DMA_Init(DMA1_Channel3, &dma_init);
/* Enable SPI TX DMA request generation */
SPI_I2S_DMACmd(SPI1, SPI_I2S_DMAReq_Tx, ENABLE);
DMA_Cmd(DMA1_Channel3, ENABLE);
NVIC_EnableIRQ(DMA1_Channel3_IRQn);
SPI_Cmd(SPI1, ENABLE);
return 0;
}
static void app_led1w_encode(const uint8_t *data, uint16_t len) {
for (uint32_t i = 0; i < APP_LED1W_ZERO_PADDING; i++) {
s_led1w_spi_buf[i] = 0x00;
}
for (uint16_t i = 0; i < len + 0; i++) {
uint16_t buf_index = i * 4 + APP_LED1W_ZERO_PADDING; // Add 0 padding
for (uint8_t j = 0; j < 4; j++) {
uint8_t bit_offset_l = (3 - j) * 2;
uint8_t bit_offset_h = (3 - j) * 2 + 1;
uint8_t buf_payload = (data[i] >> bit_offset_l & 0x01U) ? APP_LED1W_SPI_1B : APP_LED1W_SPI_0B;
buf_payload |= (((data[i] >> bit_offset_h) & 0x01U) ? APP_LED1W_SPI_1B : APP_LED1W_SPI_0B) << 4U;
s_led1w_spi_buf[buf_index + j] = buf_payload;
}
}
}
void app_led1w_irq_handler(void) {
}

View File

@ -1,4 +1,89 @@
#include <string.h>
/* Core */
#include "ch32x035.h"
/* FreeRTOS */
#include "FreeRTOS.h"
#include "task.h"
/* App */
#include "app_led1w.h"
#define APP_GRAD_STEP 4
static void hello_task(void *parameters);
int main(void) {
USART_Printf_Init(115200);
xTaskCreate(hello_task, "HELLO", 512, NULL, 4, NULL);
vTaskStartScheduler();
for (;;) {
__WFI();
}
}
static void hello_task(void *parameters) {
uint8_t data_payload[64 * 3];
app_led1w_init();
uint8_t color_r = 0xFF;
uint8_t color_g = 0x00;
uint8_t color_b = 0x00;
uint8_t dir_set = 0x01; /* 3'b001 */
memset(data_payload, 0x00, sizeof(data_payload));
for (;;) {
for (uint8_t i = 63; i > 0; i--) {
data_payload[3 * i] = data_payload[3 * (i - 1)];
data_payload[3 * i + 1] = data_payload[3 * (i - 1) + 1];
data_payload[3 * i + 2] = data_payload[3 * (i - 1) + 2];
}
data_payload[0] = color_g;
data_payload[1] = color_r;
data_payload[2] = color_b;
switch (dir_set) {
case 1: {
color_r -= APP_GRAD_STEP;
color_g += APP_GRAD_STEP;
if (color_r < APP_GRAD_STEP) {
dir_set = 2;
}
break;
}
case 2: {
color_g -= APP_GRAD_STEP;
color_b += APP_GRAD_STEP;
if (color_g < APP_GRAD_STEP) {
dir_set = 4;
}
break;
}
case 4: {
color_b -= APP_GRAD_STEP;
color_r += APP_GRAD_STEP;
if (color_b < APP_GRAD_STEP) {
dir_set = 1;
}
break;
}
default:
break;
}
app_led1w_write(data_payload, 64);
vTaskDelay(pdMS_TO_TICKS(16));
}
}