The Pico In C: A 1-Wire PIO Program
Written by Harry Fairhead   
Wednesday, 28 April 2021
Article Index
The Pico In C: A 1-Wire PIO Program
A PIO Project
Reading The Temperature

Start a new PIO project and create a file called DS1820.c and DS1820.pio. The PIO program starts off with a presence pulse and, as this is long compared to the clock time, we use a loop set by the C program. As you generally don’t need a presence pulse when reading data from a device, we can use a zero value to indicate that the operation is a read, not a write.

That is, you use the program by pushing data onto the FIFO – the first byte starts the program off and if it is zero it starts a read operation and otherwise starts a write operation with its value setting the length of the initialization pulse:

.program DS1820 
  	pull block
  	mov x, osr
  	jmp !x, read
write:	set pindirs, 1 
set pins, 0
jmp x--,loop1
set pindirs, 0 [31]
wait 1 pin 0 [31]

Once the write part of the code gets started, the non-zero value passed in via the FIFO is used to create a long, 500µs, low pulse which the slave responds to with a 120µs low presence plus. The final instruction waits for the end of the pulse so that we can start to send some data.

The second byte pushed onto the FIFO gives the number of bytes to send and these are pushed onto the stack to follow. Notice that if there are more than four or five then the program might stall until the FIFO has space.

 	 pull block
mov x, osr
pull block
set y, 7
set pindirs, 1
set pins, 0 [1]
out pins,1 [31]
set pins, 1 [20]
jmp y--,bit1
jmp x--,bytes1
set pindirs, 0 [31]
jmp again

You can see that the inner loop starting at bit1 takes the data byte in the OSR and sends it out to the GPIO line, a bit at a time. The first instruction in the loop generates the short start pulse and the second instruction sets the line high or low for 32 clock cycles. The final instruction in the loop provides the space between the bit frames. The loop repeats until all eight bits have been sent when the outer loop gets another byte to send, if there is one. If not, the program restarts and waits for the next set of data.

The read part of the program is very similar to the write:

pull block
mov x, osr
set y, 7
set pindirs, 1
set pins, 0 [1]
set pindirs, 0 [5]
in pins,1 [10]
jmp y--,bit2
jmp x--,bytes2

In this case the only data we need from the FIFO is the number of bytes to read. This is stored in the X register and controls the number of bytes processed. The inner loop, starting at bit2, reads each bit in turn. The first three instructions change the line to output, send the short start pulse and sets the line back to input. The in instruction samples the line after a short delay and gets the data which is auto-pushed onto the FIFO ready for the C program to read. Notice that if the C program fails to read the data then the loop stalls, which is fine as long as the 1-Wire device can live with a pause – the DS18B20 can.

The entire program is 29 instructions, which does leave space for instructions to toggle another GPIO line for debugging purposes. It is very probable that it can be made shorter.

Next we move on the C program. We first need an initialization function:

uint DS18Initalize(PIO pio, int gpio)
uint offset = pio_add_program(pio, &DS1820_program);
uint sm = pio_claim_unused_sm(pio, true);
pio_gpio_init(pio, gpio);
pio_sm_config c = DS1820_program_get_default_config(
sm_config_set_clkdiv_int_frac(&c, 255, 0);
sm_config_set_set_pins(&c, gpio, 1);
sm_config_set_out_pins(&c, gpio, 1);
sm_config_set_in_pins(&c, gpio);
sm_config_set_in_shift(&c, true, true, 8);
pio_sm_init(pio0, sm, offset, &c);
pio_sm_set_enabled(pio0, sm, true);
return sm;

The frequency is selected to allow the pulse times to be implemented using delays from 1 to 31.



Last Updated ( Wednesday, 02 November 2022 )