ESP32 ULP assembler I2C_WR

Valerii
Posts: 16
Joined: Wed Dec 27, 2017 4:20 pm

ESP32 ULP assembler I2C_WR

Postby Valerii » Tue Feb 20, 2018 11:24 am

Hi, I'm trying to communicate via i2c interface and faced next probem.
According to tutorial:

Code: Select all

I2C_WR      0x20, 0x33, 7, 0, 1      // Write byte 0x33 to sub-address 0x20 of slave with address set in SENS_I2C_SLAVE_ADDR1.
In my case I want to readout date from variable and write it to i2c

Code: Select all

//here var becomes 0x1234
move r1, var		  
ld      r0, r1, 0       	      // load value to r0
i2c_wr  0x22, r0, 7,  0, 0    //send 0x34 part of R0
i2c_wr  0x22, r0, 15,  8, 0    //send 0x12 part of R0
compiler returns
Error: syntax error. Input text was r0.
Error: syntax error. Input text was r0.
both for lines starting from i2c_wr.

How to work with this command correctly?

Palonso
Posts: 95
Joined: Tue Sep 24, 2019 8:43 pm

Re: ESP32 ULP assembler I2C_WR and Pulse counter

Postby Palonso » Wed Sep 09, 2020 7:17 pm

Hi,

Did you find how to fix this? I'm facing a similar problem:

Code: Select all

pulse_count.ulp.S:38: Error: syntax error. Input text was r1.
pulse_count.ulp.S:38: Error: 
pulse_count.ulp.S:102: Error: syntax error. Input text was r2.
pulse_count.ulp.S:102: Error: 
pulse_count.ulp.S:104: Error: syntax error. Input text was r1.
pulse_count.ulp.S:104: Error: 
where in line 38 I have:

Code: Select all

	/* Next input signal edge expected: 0 (negative) or 1 (positive) */
	.global next_edge
next_edge:
	.long 0
	.long 0

	/* Counter started when signal value changes.
	   Edge is "debounced" when the counter reaches zero. */
	.global debounce_counter
debounce_counter:
	.long 0
	.long 0
in line 102:

Code: Select all

	.global next_io
next_io:
	//Load io_number
	move r3, io_number
	add r3, r3, r1
	ld r3, r3, 0
and line 104 is:

Code: Select all

	/* Lower 16 IOs and higher need to be handled separately,
	 * because r0-r3 registers are 16 bit wide.
	 * Check which IO this is.
	 */
	move r0, r3
any idea of what's happening?
The code it's a slightly modified version of the ulp pulse count example.

Regards,
P

UPDATE:
Here I leave some log printed when trying to compile using idf.py:

Code: Select all

FAILED: 
esp-idf/components/ulp_components-prefix/src/ulp_components-stamp/ulp_components-build 
esp-idf/components/ulp_components/ulp_components.bin 
esp-idf/components/ulp_components/ulp_components.ld 
esp-idf/components/ulp_components/ulp_components.h 
esp-idf/components/ulp_components/ulp_components.map 
esp-idf/components/ulp_components/ulp_components.sym 
esp-idf/components/ulp_components/esp32.ulp.ld 
esp-idf/components/ulp_components/ulp_components 

cd /home/pablo/Project/Firmware/build/esp-idf/components/ulp_components && /usr/bin/cmake --build /home/pablo/Project/Firmware/build/esp-idf/components/ulp_components --target build
[1/9] Generating esp32.ulp.ld
[2/9] Generating pulse_count.ulp.S
[3/9] Generating wake_up.ulp.S
[4/9] Building ASM object CMakeFiles/ulp_components.dir/wake_up.ulp.S.obj
[5/9] Building ASM object CMakeFiles/ulp_components.dir/pulse_count.ulp.S.obj

FAILED: CMakeFiles/ulp_components.dir/pulse_count.ulp.S.obj 
esp32ulp-elf-as                                      
-I/home/pablo/Project/Firmware/components/include 
-I/home/pablo/Project/Firmware/build/config 
-I/home/pablo/esp/esp-idf/components/newlib/platform_include 
-I/home/pablo/esp/esp-idf/components/freertos/include 
-I/home/pablo/esp/esp-idf/components/freertos/xtensa/include 
-I/home/pablo/esp/esp-idf/components/heap/include 
-I/home/pablo/esp/esp-idf/components/log/include 
-I/home/pablo/esp/esp-idf/components/lwip/include/apps 
-I/home/pablo/esp/esp-idf/components/lwip/include/apps/sntp 
-I/home/pablo/esp/esp-idf/components/lwip/lwip/src/include 
-I/home/pablo/esp/esp-idf/components/lwip/port/esp32/include 
-I/home/pablo/esp/esp-idf/components/lwip/port/esp32/include/arch 
-I/home/pablo/esp/esp-idf/components/soc/src/esp32/. 
-I/home/pablo/esp/esp-idf/components/soc/src/esp32/include 
-I/home/pablo/esp/esp-idf/components/soc/include 
-I/home/pablo/esp/esp-idf/components/esp_rom/include 
-I/home/pablo/esp/esp-idf/components/esp_common/include 
-I/home/pablo/esp/esp-idf/components/esp_system/include 
-I/home/pablo/esp/esp-idf/components/xtensa/include 
-I/home/pablo/esp/esp-idf/components/xtensa/esp32/include 
-I/home/pablo/esp/esp-idf/components/esp32/include 
-I/home/pablo/esp/esp-idf/components/driver/include 
-I/home/pablo/esp/esp-idf/components/driver/esp32/include 
-I/home/pablo/esp/esp-idf/components/esp_ringbuf/include 
-I/home/pablo/esp/esp-idf/components/efuse/include 
-I/home/pablo/esp/esp-idf/components/efuse/esp32/include 
-I/home/pablo/esp/esp-idf/components/espcoredump/include 
-I/home/pablo/esp/esp-idf/components/esp_timer/include 
-I/home/pablo/esp/esp-idf/components/esp_ipc/include 
-I/home/pablo/esp/esp-idf/components/soc/soc/esp32/. 
-I/home/pablo/esp/esp-idf/components/soc/soc/esp32/include 
-I/home/pablo/esp/esp-idf/components/soc/soc/esp32/../include 
-I/home/pablo/esp/esp-idf/components/vfs/include 
-I/home/pablo/esp/esp-idf/components/esp_wifi/include 
-I/home/pablo/esp/esp-idf/components/esp_wifi/esp32/include 
-I/home/pablo/esp/esp-idf/components/esp_event/include 
-I/home/pablo/esp/esp-idf/components/esp_netif/include 
-I/home/pablo/esp/esp-idf/components/esp_eth/include 
-I/home/pablo/esp/esp-idf/components/tcpip_adapter/include 
-I/home/pablo/esp/esp-idf/components/app_trace/include 
-I/home/pablo/esp/esp-idf/components/nvs_flash/include 
-I/home/pablo/esp/esp-idf/components/spi_flash/include 
-I/home/pablo/esp/esp-idf/components/mbedtls/port/include 
-I/home/pablo/esp/esp-idf/components/mbedtls/mbedtls/include 
-I/home/pablo/esp/esp-idf/components/mbedtls/esp_crt_bundle/include 
-I/home/pablo/esp/esp-idf/components/mqtt/esp-mqtt/include 
-I/home/pablo/esp/esp-idf/components/nghttp/port/include 
-I/home/pablo/esp/esp-idf/components/nghttp/nghttp2/lib/includes 
-I/home/pablo/esp/esp-idf/components/tcp_transport/include 
-I/home/pablo/esp/esp-idf/components/esp-tls 
-I/home/pablo/esp/esp-idf/components/json/cJSON 
-I/home/pablo/esp/esp-idf/components/app_update/include 
-I/home/pablo/esp/esp-idf/components/bootloader_support/include 
-I/home/pablo/esp/esp-idf/components/esp_http_client/include 
-I/home/pablo/esp/esp-idf/components/esp_https_ota/include 
-I/home/pablo/esp/esp-idf/components/esp_adc_cal/include 
-I/home/pablo/esp/esp-idf/components/bt/include 
-I/home/pablo/esp/esp-idf/components/bt/common/osi/include 
-I/home/pablo/esp/esp-idf/components/bt/host/bluedroid/api/include/api 
-I/home/pablo/esp/esp-idf/components/ulp/include 
-o CMakeFiles/ulp_components.dir/pulse_count.ulp.S.obj 
-c pulse_count.ulp.S

pulse_count.ulp.S: Mensajes del ensamblador:
pulse_count.ulp.S:38: Error: syntax error. Input text was r1.
pulse_count.ulp.S:38: Error: 
pulse_count.ulp.S:93: Error: syntax error. Input text was r1.
pulse_count.ulp.S:93: Error: 
pulse_count.ulp.S:102: Error: syntax error. Input text was r2.
pulse_count.ulp.S:102: Error: 
pulse_count.ulp.S:104: Error: syntax error. Input text was r1.
pulse_count.ulp.S:104: Error: 
ninja: build stopped: subcommand failed.
[594/1248] Building C object esp-idf/nghttp/CMakeFi.../__idf_nghttp.dir/nghttp2/lib/nghttp2_session.c.obj
ninja: build stopped: subcommand failed.
ninja failed with exit code 1
UPDATE2:
I tried changing the code back as it was and compiled, so I can assume that the problem is in the code.
Here I leave my code, being honest I can't find the error:

Code: Select all

/* ULP assembly files are passed through C preprocessor firST, so include directives
   AND C macros may be used in these files 
 */
#include "soc/rtc_cntl_reg.h"
#include "soc/rtc_io_reg.h"
#include "soc/soc_ulp.h"

	/* Define variables, which go into .bss section (zero-initialized data) */
	/* All variables are arrays where [0] are for IN0 AND [1] for IN1 */
	.bss
	/* Next input signal edge expected: 0 (negative) or 1 (positive) */
	.global next_edge
next_edge:
	.long 0
	.long 0

	/* Counter STarted when signal value changes.
	   Edge is "debounced" when the counter reaches zero. */
	.global debounce_counter
debounce_counter:
	.long 0
	.long 0

	/* Value to which debounce_counter gets reset.
	   Set by the main program. */
	.global debounce_max_count
debounce_max_count:
	.long 0
	.long 0

	/* Total number of signal edges acquired */
	.global edge_count
edge_count:
	.long 0
	.long 0

	/* Number of edges to acquire before waking up the SoC.
	   Set by the main program. */
	.global edge_count_to_wake_up
edge_count_to_wake_up:
	.long 0
	.long 0

	/* RTC IO number used to sample the input signal.
	   Set by main program. */
	.global io_number
io_number:
	.long 0
	.long 0

	//En que pin se debe contar pulsos:
	//Input_0	 = 0b0000
	//Input_1 	 = 0b0001
	//Both  = 0b001X
	.global pulse_cnt_pin
pulse_cnt_pin:
	.long 0

/*---------------------------------------------------------------*/
	//Code goes into .text section

	.text
	.global entry
entry:
	//Reviso que pin debe contar pulsos
	MOVE R3, pulse_cnt_pin			//Se carga la direccion de pulse_cnt_pin en R3
	LD R1, R3, 0					//Se carga el valor de pulse_cnt_pin en R1
	AND R1, R1, 0x0003				//Me quedo con los ultimos dos BIT (describen que entradas ver)
	
	MOVE R0, 2
	JUMPR next_io, R1, gt			//Si R1<2, solo leo ese pin
	MOVE R1, 1						//En R1>=2 tengo que leer ambas entradas, se re evalua al final

	.global next_io
next_io:
	//Load io_number
	MOVE R3, io_number				//Guardo la direccion del io_number a leer en R3
	ADD R3, R3, R1					//Avanzo "el puntero" a la posicion que corresponda
	LD R3, R3, 0					//Cargo lo que eSTa en esa direccion y remplazo R3

	/* Lower 16 IOs AND higher need to be hANDled separately,
	 * because R0-R3 regiSTers are 16 bit wide.
	 * Check which IO this is.
	 */
	MOVE R0, R3						//Se copia el valor de R3 en R0

	//Read the value of lower 16 RTC IOs into R0
	READ_RTC_REG(RTC_GPIO_IN_REG, RTC_GPIO_IN_NEXT_S, 16)
	RSH R0, R0, R3					//Se coloca en la posicion 0 el bit de interes

read_done:
	AND R0, R0, 1					//Se filtra el BIT0 del regiSTro R0
	//STate of input changed?

	//Load next_edge
	MOVE R3, next_edge				//Se carga la direccion de next_edge
	ADD R3, R3, R1					//Avanzo "el puntero" a la posicion que corresponda
	LD R3, R3, 0					//Se carga el valor de next_edge en R3

	ADD R3, R0, R3					//Se suman R0 y R3 y se guarda en R3
	AND R3, R3, 1					//Se filtra el BIT0 del regiSTro R3
	JUMP changed, eq 				//JUMP if laST ALU operation result was zero

	//Not changed: Reset debounce_counter to debounce_max_count
	MOVE R3, debounce_max_count		//Se carga la direccion de debounce_max_count en R3
	ADD R3, R3, R1					//Avanzo "el puntero" a la posicion que corresponda
	MOVE R2, debounce_counter		//Se carga la direccion de debounce_counter en R2
	ADD R2, R2, R1					//Avanzo "el puntero" a la posicion que corresponda
	LD R3, R3, 0					//Se carga el valor de debounce_max_count
	ST R3, R2, 0					//Se guarda el valor de debounce_max_count en debounce_counter

	/* End program */
	JUMP check_end

	.global changed
changed:
	//Input STate changed
	//Has debounce_counter reached zero?
	MOVE R3, debounce_counter		//Se carga la direccion de debounce_counter en R3
	ADD R3, R3, R1					//Avanzo "el puntero" a la posicion que corresponda
	LD R2, R3, 0					//Se carga el valor de debounce_counter en R2
	ADD R2, R2, 0 					//dummy ADD to use "JUMP if ALU result is zero"
	JUMP edge_detected, eq			//Si el debounce counter llego a cero, aumento la cantidad de flancos (edge_detected)

	//Si aun no, eSToy en ventANDa de rebote: decremento el contador.
	SUB R2, R2, 1
	ST R2, R3, 0

	//End program
	JUMP check_end

	.global edge_detected
edge_detected:
	//Reset debounce_counter to debounce_max_count
	MOVE R3, debounce_max_count		//Se carga la direccion de debounce_max_count en R3
	ADD R3, R3, R1					//Avanzo "el puntero" a la posicion que corresponda
	MOVE R2, debounce_counter		//Se carga la direccion de debounce_counter en R2
	ADD R2, R2, R1					//Avanzo "el puntero" a la posicion que corresponda
	LD R3, R3, 0					//Se carga el valor de debounce_max_count
	ST R3, R2, 0					//Se guarda el valor de debounce_max_count en debounce_counter

	//Cambio next_edge para esperar el proximo flanco
	MOVE R3, next_edge				//Se carga la direccion de next_edge en R3
	ADD R3, R3, R1					//Avanzo "el puntero" a la posicion que corresponda
	LD R2, R3, 0					//Se carga el valor de next_edge en R2

	ADD R2, R2, 1					//Se le suma 1 a R2
	AND R2, R2, 1					//Se filtra el BIT0 de R2

	ST R2, R3, 0					//Se guarda el valor de R2 en next_edge

	//Aumento la cuenta de flancos
	MOVE R3, edge_count				//Se carga la direccion de edge_count
	ADD R3, R3, R1					//Avanzo "el puntero" a la posicion que corresponda
	LD R2, R3, 0					//Se carga el valor de edge_count en R2
	ADD R2, R2, 1					//Le sumo 1
	ST R2, R3, 0					//Se guarda el valor de R2 en edge_count

	//Si llego cierta cantidad de flancos, despierto el dispositivo (necesario(?))
	MOVE R3, edge_count_to_wake_up	//
	LD R3, R3, R1					//
	SUB R3, R3, R2					//
	JUMP wake_up, eq				//

	//Not yet. End program
	//JUMP check_end

	.global check_end
check_end:
	MOVE R3, pulse_cnt_pin			//Se carga la direccion de pulse_cnt_pin en R3
	LD R2, R3, 0					//Se carga el valor de pulse_cnt_pin en R2
	AND R2, R2, 0x0003				//Me quedo con los ultimos dos BIT (describen que entradas ver)

	MOVE R0, 2						//Se carga el valor 2 en R0
	JUMPR end_ulp, R2, gt			//Si R2 < 2(R0), termino el programa

	MOVE R0, 1						//Si se leen ambos pines tengo que revisar cual fue el ultimo que lei
	JUMPR end_ulp, R1, gt			//Si el ultimo que lei fue [0] termino el programa
	MOVE R1, 0						//Si el ultimo fue [1], cambio el pin a revisar [1]-->[0]
	JUMP next_io					//Una vez cambiado el puntero, ejecuto la rutina nuevamente

	.global end_ulp
end_ulp:
	HALT							//Sino termino
The idea is to count pulses in two inputs (configurable: just one, the other or both) so the program checks wich input has to read and count pulses and then goes to sleep.

I would appreciate if someone finds where the error.

Thanks,
P

PS: there are some comments (in spanish) just ignore them, they are more likely to help newbies understand how ULP programming works

UPDATE3:
I found my mistake, on JUMPR instruction I compare R0 with another RX register (which I tought I could) I'll try to change the conditions a bit in order to make it work only with R0, yet I think it would be awesome to compare between registers directly.

After changing them it remain a single error:

Code: Select all

pulse_count.ulp.S:93: Error: syntax error. Input text was R1.
pulse_count.ulp.S:93: Error: 
ninja: build stopped: subcommand failed.
Which correspond to:

Code: Select all

	//Cuando inicio el programa empiezo por el lugar [0]
	//La segunda vuelta paso al lugar [1] y termino el programa
	.text
	.global entry
entry:
	//Reviso que pin debe contar pulsos
	MOVE R3, pulse_cnt_pin			//Se carga la direccion de pulse_cnt_pin en R3
	LD R1, R3, 0					//Se carga el valor de pulse_cnt_pin en R1
	AND R1, R1, 0x0003				//Me quedo con los ultimos dos BIT (describen que entradas ver)
	
	MOVE R0, R2
	JUMPR next_io, 2, lt			//Si R1<2, solo leo ese pin
	MOVE R2, 1						//En R1>=2 tengo que leer ambas entradas, se re evalua al final

	.global next_io
next_io:
	//Load io_number
	MOVE R3, io_number				//Guardo la direccion del io_number a leer en R3
	ADD R3, R3, R1					//Avanzo "el puntero" a la posicion que corresponda
	LD R3, R3, 0					//Cargo lo que esta en esa direccion y remplazo R3
And I can't find what's the problem.

By the way I have the next question: there are "negative" values with the ulp? does overflow flag sets when 'SUB'ing to 0?

Regards,
P

(FINAL) UPDATE (?):
The problem was the LD command, I was using R1 as one of the parameters, but needed a 10 bit value. Yet that would have been faster to solve if the compiler show the syntax problem closer (because it was on line 184).

Still I want to know more about how the ALU flags work, regarding whats considered an overflow and if negative number are possible to use.

Best regards,
P

Who is online

Users browsing this forum: No registered users and 48 guests