ESP32-C6 baremetal led ws2812 blink riscv assembly
Posted: Fri Jul 03, 2026 1:37 pm
This RISC-V assembly program blinks the LED to test the various colors without using the IDF SDK.
It also copies data from the `.data` section and initializes the `.bss` section.
You may need to modify the compiler and flashing tool paths in the Makefile.
makefile :
memmap.ld :
It also copies data from the `.data` section and initializes the `.bss` section.
You may need to modify the compiler and flashing tool paths in the Makefile.
Code: Select all
/* assembly risc-v */
/* blink led 8 white flash, 2 blue, 5 red, 4 green, 3 white
/*******************************************/
/* CONSTANTES */
/*******************************************/
.equ LED_PIN, 8
.equ WHITE,0
.equ RED, 1
.equ GREEN,2
.equ BLUE,3
.equ DELAIt0l, 21 # 800 nanos (80mhz)
.equ DELAIt0h, 10 # 350
.equ DELAIt1l, 15 # 600
.equ DELAIt1h, 18 # 700
.equ GPIO_MATRIX, 0x60091000
.equ GPIO_OUT_REG, 0x4
.equ GPIO_OUT_W1TS_REG, 0x8
.equ GPIO_OUT_W1TC_REG, 0xC
.equ GPIO_ENABLE_REG, 0x20
.equ GPIO_ENABLE_W1TS_REG,0x24
.equ GPIO_ENABLE_W1TC_REG,0x28
.equ GPIO_PIN_REG, 0x74 + (4*LED_PIN)
.equ GPIO_FUNC8_OUT_SEL_CFG_REG, 0x554 + (4*LED_PIN)
.equ GPIO_STATUS_REG, 0x44
.equ GPIO_CLOCK_GATE_REG ,0x062C
.equ GPIO_DATE_REG, 0x06FC
.equ PCR, 0x60096000 # clock, reset
.equ PCR_SYSCLK_CONF_REG, 0x0110
.equ PCR_IOMUX_CLK_CONF_REG, 0x00EC
.equ PCR_IOMUX_CONF_REG, 0x00E8
.equ TIMG0, 0x60008000
.equ TIMG1, 0x60009000
.equ TIMG_WDTCONFIG0_REG, 0x0048
.equ TIMG_WDTWPROTECT_REG, 0x0064 # paragraphe 14.5
.equ VALUEPROCT, 0x50d83aa1
.equ RTC_WDT, 0x600B1C00 # RTC Watch Dog Timer
.equ RTC_WDT_CONFIG0_REG, 0x0
.equ RTC_WDT_CONFIG1_REG, 0x4
.equ RTC_WDT_FEED_REG, 0x0014
.equ RTC_WDT_WPROTECT_REG, 0x0018
.equ RTC_WDT_SWD_WPROTECT_REG, 0x0020
.equ RTC_WDT_SWD_CONFIG_REG, 0x001C
/*******************************************/
/* DONNEES INITIALISEES */
/*******************************************/
.data
inbflash: .int 8
/***********************************************/
/* Données non initialisées */
/***********************************************/
.bss
iColor: .skip 4
/*******************************************/
/* CODE PROGRAMME */
/*******************************************/
.text
.align 2
.global main
/************************************/
/* Main */
/***********************************/
main: # INFO: main
.int 0xAEDB041D, 0xAEDB041D # magic number
li sp,0x4080CC00 # stack address
li a0,RED
la a1,iColor # color red verify init bss
sw a0,(a1)
call initStart # initialisations
la a0,inbflash # flash number verify copy data
lw a0,(a0)
la a1,iColor # if init bss ok, this color is white (0)
lw a1,(a1)
li a2,20 #
call led2812Eclats
li a0,100
call attendre
li a0,2 # flash number
li a1,BLUE # color blue
li a2,20 #
call led2812Eclats
li a0,100
call attendre
1:
li a0,5 # flash number
li a1,RED # color red
li a2,20 #
2:
call led2812Eclats
li a0,100
call attendre
li a0,4 # flash number
li a1,GREEN # color green
li a2,20 #
call led2812Eclats
li a0,3 # flash number
li a1,WHITE # color white
li a2,20 #
call led2812Eclats
10:
j 10b # end loop
.align 2
/************************************/
/* initialisation */
/***********************************/
/* a0 paramètre */
initStart: # INFO: initStart
addi sp, sp, -8 # save registres
sw ra, 0(sp)
li t0,0x28010200
li t1,PCR
sw t0,PCR_SYSCLK_CONF_REG(t1)
li t0,TIMG0 # disable timer watchdog
li t1,VALUEPROCT
sw t1,TIMG_WDTWPROTECT_REG(t0)
li t1,0
sw t1,TIMG_WDTCONFIG0_REG(t0)
li t1,1
sw t1,TIMG_WDTWPROTECT_REG(t0)
li t1,RTC_WDT # disable watchdog
li t0,0x50D83AA1
sw t0,RTC_WDT_WPROTECT_REG(t1)
li t0,0x50D83AA1
sw t0,RTC_WDT_SWD_WPROTECT_REG(t1)
li t0,0x40000000
sw t0,RTC_WDT_SWD_CONFIG_REG(t1)
sw x0,RTC_WDT_CONFIG0_REG(t1)
sw x0,RTC_WDT_CONFIG1_REG(t1)
li t0,1
sw t0,RTC_WDT_SWD_WPROTECT_REG(t1)
la t1,iFlashdata # copy data in ram
lw t1,(t1)
la t2,iRamdata
lw t2,(t2)
la t3,iRamBss
lw t3,(t3)
1: # boucle de copie de la data en rom
lw t0,(t1) # vers la data en ram
sw t0,(t2)
addi t1,t1,4
addi t2,t2,4
bltu t2,t3,1b
# initialisation .bss
la t2,iFinRamBss
lw t2,(t2)
2:
sw x0,(t3) # move zero in bss area
addi t3,t3,4
bltu t3,t2,2b
100:
lw ra, 0(sp)
addi sp, sp, 8
ret
.align 2
iFlashdata: .int _debutFlashData
iRamdata: .int _debutRamData
iRamBss: .int _debutRamBss
iFinRamBss: .int _finRamBss
iDebutTas: .int _debutTas
/************************************/
/* init gpio */
/***********************************/
/* a0 pin led */
initGpioLed: # INFO: initGpioLed
addi sp, sp, -8
sw ra, 0(sp)
li t4,GPIO_MATRIX
li t0,1
sll t2,t0,a0 # bit pin 8
sw t2,GPIO_ENABLE_W1TS_REG(t4)
li t0,0x280 #
sw t0,GPIO_FUNC8_OUT_SEL_CFG_REG(t4)
li t4,GPIO_MATRIX
li t0,0
sw t0,GPIO_PIN_REG(t4)
100:
lw ra, 0(sp)
addi sp, sp, 8
ret
/************************************/
/* boucle attente */
/***********************************/
/* a0 valeur en milliseconde */
.align 2
attendre: # INFO: attendre
addi sp, sp, -12 # save des registres
sw ra, 0(sp)
sw t0, 4(sp)
sw t1, 8(sp)
li t0,16 # approximatif
sll t1,a0,t0
li t0,12
sll a0,a0,t0
add a0,a0,t1
1: # loop
addi a0,a0, -1 # decrement indice
bne a0,x0,1b
lw ra, 0(sp)
lw t0, 4(sp)
lw t1, 8(sp)
addi sp, sp, 12 # restaur registres
jr ra
.align 2
/************************************/
/* blink led ws2812 */
/***********************************/
/* a0 nombre eclats */
/* a1 contient la couleur 0 white 1 red 2 green 3 blue */
/* a2 contient le niveau */
led2812Eclats: # INFO: led2812Eclats
addi sp, sp, -16 # save registres
sw ra, 0(sp)
sw s0, 4(sp)
sw s1, 8(sp)
sw s2, 12(sp)
mv s0,a0
mv s1,a1
mv s2,a2
li a0,LED_PIN
call initGpioLed
li a0,000 # raz led
li a1,000
li a2,000
call envoiComLed
li a0,10
call attendre
1:
li t0,RED
bne s1,t0,2f
mv a0,s2
li a1,000
li a2,000
j 5f
2:
li t0,GREEN
bne s1,t0,3f
li a0,0
mv a1,s2
li a2,000
j 5f
3:
li t0,BLUE
bne s1,t0,4f
li a0,0
li a1,0
mv a2,s2
j 5f
4:
mv a0,s2
mv a1,s2
mv a2,s2
5:
call envoiComLed
li a0,500 # avant 250
call attendre
li a0,000 # raz led
li a1,000
li a2,000
call envoiComLed
li a0,500
call attendre
addi s0,s0,-1
bgtz s0,1b # et boucle
100:
lw ra, 0(sp)
lw s0, 4(sp)
lw s1, 8(sp)
lw s2, 12(sp)
addi sp, sp, 16
ret
.align 2
/************************************/
/* envoi des codes couleurs vers le pin LED */
/***********************************/
/* a0 contient la couleur rouge 0 255 */
/* a1 contient la couleur verte 0 255 */
/* a2 contient la couleur bleue 0 255 */
/* attention ne rien mettre entre chaque envoi de couleur */
envoiComLed: # INFO: envoiComLed
addi sp, sp, -12 # save registres
sw ra, 0(sp)
sw s0, 4(sp)
sw s1, 8(sp)
mv s0,a0
li s1,1
slli s1,s1,LED_PIN
li t1,7 # debut par le bit 7
li t4,GPIO_MATRIX
1: # couleur verte
srl t3,s0,t1
andi t3,t3,1 # test bit 0
bnez t3,2f
sw s1,GPIO_OUT_W1TS_REG(t4)
li a0,DELAIt0h # 1 cycle
call cycleLedWs2812 # 2 cycles
sw s1,GPIO_OUT_W1TC_REG(t4)
li a0,DELAIt0l # 1 cycle
call cycleLedWs2812 # 2 cycles
j 3f
2:
sw s1,GPIO_OUT_W1TS_REG(t4)
li a0,DELAIt1h # 1 cycle
call cycleLedWs2812 # 2 cycles
sw s1,GPIO_OUT_W1TC_REG(t4) # clear
li a0,DELAIt1l # 1 cycle
call cycleLedWs2812 # 2 cycles
3:
addi t1,t1,-1
bgez t1,1b
li t1,7
4: # couleur rouge
srl t3,a1,t1
andi t3,t3,1
bnez t3,5f
sw s1,GPIO_OUT_W1TS_REG(t4)
li a0,DELAIt0h # 1 cycle
call cycleLedWs2812 # 2 cycles
sw s1,GPIO_OUT_W1TC_REG(t4) # clear
li a0,DELAIt0l # 1 cycle
call cycleLedWs2812 # 2 cycles
j 6f
5:
sw s1,GPIO_OUT_W1TS_REG(t4)
li a0,DELAIt1h # 1 cycle
call cycleLedWs2812 # 2 cycles
sw s1,GPIO_OUT_W1TC_REG(t4)
li a0,DELAIt1l # 1 cycle
call cycleLedWs2812 # 2 cycles
6:
addi t1,t1,-1
bgez t1,4b
li t1,7
7: # coukeur bleue
srl t3,a2,t1
andi t3,t3,1
bnez t3,8f
sw s1,GPIO_OUT_W1TS_REG(t4)
li a0,DELAIt0h # 1 cycle
call cycleLedWs2812 # 2 cycles
sw s1,GPIO_OUT_W1TC_REG(t4)
li a0,DELAIt0l # 1 cycle
call cycleLedWs2812 # 2 cycles
j 9f
8:
sw s1,GPIO_OUT_W1TS_REG(t4)
li a0,DELAIt1h # 1 cycle
call cycleLedWs2812 # 2 cycles
sw s1,GPIO_OUT_W1TC_REG(t4) # clear
li a0,DELAIt1l # 1 cycle
call cycleLedWs2812 # 2 cycles
9:
addi t1,t1,-1
bgez t1,7b
100:
lw ra, 0(sp)
lw s0, 4(sp)
lw s1, 8(sp)
addi sp, sp, 12
ret
.align 2
/************************************/
/* loop cycles Led */
/***********************************/
/* a0 loop number */
cycleLedWs2812: # INFO: cycleLedWs2812
1:
addi a0,a0,-1 # 1 cycle * N
bnez a0,1b # 1 cycles * N + 2 cycle end
ret # 2 cycles
.align 2
/************************************/
/* Exemple */
/***********************************/
/* a0 paramètre */
exempleFonction: # INFO: exempleFonction
addi sp, sp, -8 # save registres
sw ra, 0(sp)
100:
lw ra, 0(sp)
addi sp, sp, 8
ret
Code: Select all
ARMGNU ?= C:/Espressif/tools/riscv32-esp-elf/esp-15.2.0_20251204/riscv32-esp-elf/bin
#ARMGNU ?= C:\Espressif\tools\riscv32-esp-elf\esp-15.2.0_20251204\riscv32-esp-elf\riscv32-esp-elf\bin
ARMGNU1 ?= C:\PrincipalA\Outils\tools\arm-gnu-toolchain-13.3.rel1-mingw-w64-i686-arm-none-eabi\arm-none-eabi\bin
AOPS = -mabi=ilp32 -march=rv32i_m_zbs_zicsr_f_zba
all : fctledasmD.flash
fctledasmD.o : fctledasmD.s
$(ARMGNU)/riscv32-esp-elf-as.exe $(AOPS) fctledasmD.s -o fctledasmD.o
fctledasmD.bin : fctledasmD.o
$(ARMGNU)/riscv32-esp-elf-ld.exe -T memmap.ld fctledasmD.o -o fctledasmD.elf -M >fctledasmD_map.txt
$(ARMGNU)/riscv32-esp-elf-objcopy -O binary fctledasmD.elf fctledasmD.bin
$(ARMGNU)/riscv32-esp-elf-objdump.exe -D fctledasmD.elf > fctledasmD_list.txt
fctledasmD.flash : fctledasmD.bin
C:\Espressif\tools\python\v6.0.1\venv\Scripts\esptool --chip esp32c6 -p com14 -b 460800 write-flash --flash-mode dio --flash-freq 80m --flash-size 2MB 0x0 fctledasmD.bin
Code: Select all
MEMORY
{
flash (rx) : ORIGIN = 0x42000000, LENGTH = 2048k
ram (rwx) : ORIGIN = 0x40800000, LENGTH = 0x80000
}
STACK_SIZE = 0x4000;
RAM_SIZE = 0x80000;
/* Section Definitions */
SECTIONS
{
.text :
{
/* KEEP(*(.vectors .vectors.*)) */
*(.text*)
*(.rodata*)
} > flash
. = ALIGN(4);
_debutFlashData = . ;
.data :
{
. = ALIGN(2);
_debutRamData = . ;
. = ALIGN(2);
*(.data*);
} > ram AT > flash
/* .bss section which is used for uninitialized data */
. = ALIGN(4); /* aligne bss pour initialisation dans pgm */
_debutRamBss = . ;
.bss (NOLOAD) :
{
*(.bss*)
*(COMMON)
} > ram
_finRamBss = . ;
.SC1 (NOLOAD):
{
. = ALIGN(8);
_debutTas = . ;
. = _debutRamData - . + RAM_SIZE - (STACK_SIZE) ;
} > ram
_finTas = . ;
/* stack section */
.stack (NOLOAD):
{
. = ALIGN(8);
. = . + STACK_SIZE;
_stack = .;
. = ALIGN(8);
} > ram
_end = . ;
}