Page 1 of 1

ESP32-C6 baremetal led ws2812 blink riscv assembly

Posted: Fri Jul 03, 2026 1:37 pm
by watchdog40
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.

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 
    
makefile :

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
memmap.ld :

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 = . ;
}