Page 1 of 1

ULP ADC read help

Posted: Wed Nov 18, 2020 6:28 pm
by bonadio
Hello

I have a running app reading the ADC channel while sleeping and the channel is set fixed in the code

Code: Select all

.set adc_channel, 5

adc r1, 0, adc_channel + 1
This code works, but now I need to pass the channel dynamically

Code: Select all

;.set adc_channel, 5

	.global adc_channel
adc_channel:
	.long 0 

adc r1, 0, adc_channel + 1
	
I comment the .set and created a variable called ulp_adc_channel and set it on the c code but this does not work.

What would be the correct way to set the channel dynamically?

I tried the following code too but did not worked

Code: Select all

	.global adc_channel
adc_channel:
	.long 0 

move r2, adc_channel
adc r1, 0, r2
	

This is the full code

Code: Select all

#include "soc/rtc_cntl_reg.h"
#include "soc/soc_ulp.h"

	/* ADC1 channel 6, GPIO34 */
	
	; .set adc_channel, 4 

	/* Configure the number of ADC samples to average on each measurement.
	   For convenience, make it a power of 2. */
	.set adc_oversampling_factor_log, 2
	.set adc_oversampling_factor, (1 << adc_oversampling_factor_log)

	/* Define variables, which go into .bss section (zero-initialized data) */
	.bss


	.global adc_channel
adc_channel:
	.long 0 

	.global last_result
last_result:
	.long 0

	/* Code goes into .text section */
	.text
	.global entry
entry:
	/* do measurements using ADC */
	/* r0 will be used as accumulator */
	move r0, 0
	/* initialize the loop counter */
	stage_rst
measure:
	/* measure and add value to accumulator */
	; adc r1, 0, adc_channel + 1
	move r2, adc_channel 
	adc r1, 0, r2
	add r0, r0, r1
	/* increment loop counter and check exit condition */
	stage_inc 1
	jumps measure, adc_oversampling_factor, lt

	/* divide accumulator by adc_oversampling_factor.
	   Since it is chosen as a power of two, use right shift */
	rsh r0, r0, adc_oversampling_factor_log
	/* averaged value is now in r0; store it into last_result */
	move r3, last_result
	st r0, r3, 0
	halt


Thanks

Re: ULP ADC read help

Posted: Wed Nov 18, 2020 10:41 pm
by boarchuz
Not directly possible.
You'll either need to include all variations of ADC instruction in the ULP program and have the ULP jump to the correct one based on a variable that can be changed by the SoC, or change the ULP program when you want to change the ADC channel.

You could try updating just the one instruction, eg.

Code: Select all

#define ULP_PROG_ADC_INSN_OFFSET 7
static void update_ulp_adc(uint8_t adc_index, uint8_t channel) {
    ulp_insn_t *adc_insn = (ulp_insn_t *)RTC_SLOW_MEM + ULP_PROG_ADC_INSN_OFFSET;
    assert(adc_insn->adc.opcode == OPCODE_ADC && "not adc instruction");
    
    ulp_insn_t new_instruction = I_ADC(adc_insn->adc.dreg, adc_index, channel);
    *adc_insn = new_instruction;
}

update_ulp_adc(0, 1); // gpio 37
update_ulp_adc(1, 9); // gpio 26
You will need to handle the possibility of a conflict.

Re: ULP ADC read help

Posted: Wed Nov 18, 2020 11:15 pm
by bonadio
Hi @boarchuz

Thanks for the response, I will go with jump inside the ULP based on a variable

[]s