Hello everyone,
there seems to be a possible source of confusion in the datasheet for the RP2350.
In particular for the PIO instruction MOV with OSR as destination.
In the datasheet it reads:
" 111: OSR (Output shift counter is reset to 0 by this operation, i.e. full)"
However, this is counterintuitive if you use autopull.
Reason being that one would assume that no autopull would be done if the OSR is full. So, if one would do, for example, MOV OSR, NULL, it should not do any autopull. However, it seems that it simply discards the OSR and does an autopull.
Here is how i came about this peculiarity. I am writing a PIO program that drives an 16 bit databus to an IPS display. As is often the case, the display controller needs some setup data, etc. So, the transfers have varying data bit-width. 8 bits for control data, 16 bits for display data, in this case.
The very first 32-bit word my PIO program uses defines the actual command (lower 8 bits), the number of data-entries to send (22 bits) and one bit to signal if any data has to be read back from the display controller.
So, once the payload is less than 32 bits in total, there are bits left in the OSR. However, only partially shifting out bits means that whatever queries the TXSTALL condition never comes true because autopull does not need to get in a new word.
Previously i used the jmp !OSRE construct to flush the OSRE, until i just tried the MOV OSR... construct. To my surprise, it worked!
In any case, it is somewhat confusing that MOV OSR... says that it will set OSR to full, but autopull still pulls in a new word after that.
But maybe it's just me doing something stupid? This is my PIO code as of now:
The switching between 8/16 bit data width is done in software as needed, simply by patching the two instructions on the fly as needed.
In any case, am i doing something wrong, or is this really some unclear documentation? I would not expect the PIO to autopull a new word as long as the OSR was not emptied (to the given threshold) if the MOV OSR... just marks it as full.
Don't get me wrong, it's great that it behaves as it does, saving the precious PIO memory! Just maybe a little mention, or some footnote, regarding the combination of autopull and MOV OSR...?
Greetings,
Chris
there seems to be a possible source of confusion in the datasheet for the RP2350.
In particular for the PIO instruction MOV with OSR as destination.
In the datasheet it reads:
" 111: OSR (Output shift counter is reset to 0 by this operation, i.e. full)"
However, this is counterintuitive if you use autopull.
Reason being that one would assume that no autopull would be done if the OSR is full. So, if one would do, for example, MOV OSR, NULL, it should not do any autopull. However, it seems that it simply discards the OSR and does an autopull.
Here is how i came about this peculiarity. I am writing a PIO program that drives an 16 bit databus to an IPS display. As is often the case, the display controller needs some setup data, etc. So, the transfers have varying data bit-width. 8 bits for control data, 16 bits for display data, in this case.
The very first 32-bit word my PIO program uses defines the actual command (lower 8 bits), the number of data-entries to send (22 bits) and one bit to signal if any data has to be read back from the display controller.
So, once the payload is less than 32 bits in total, there are bits left in the OSR. However, only partially shifting out bits means that whatever queries the TXSTALL condition never comes true because autopull does not need to get in a new word.
Previously i used the jmp !OSRE construct to flush the OSRE, until i just tried the MOV OSR... construct. To my surprise, it worked!
In any case, it is somewhat confusing that MOV OSR... says that it will set OSR to full, but autopull still pulls in a new word after that.
But maybe it's just me doing something stupid? This is my PIO code as of now:
Code:
.pio_version 1.program cmd.side_set 3.wrap_targetcmd_start:; start a cmd transfer, may have extra bytes to sendmov PINDIRS, ~NULL[0]side 0x7; RD = 1, WR = 1, RS = 1set data pins as outputout pins, 8[0]side 0x7; RD = 1, WR = 1, RS = 1load cmd byte to data pinsout y, 23[2] side 0x6; RD = 1, WR = 1, RS = 0load num payload tx into yout x, 1[2] side 0x4; RD = 1, WR = 0, RS = 0load read flag into xjmp !y cmd_read[1] side 0x6; RD = 1, WR = 1, RS = 0if no payload write, jump to readjmp y-- cmd_write_loop[0] side 0x7; RD = 1, WR = 1, RS = 1if payload write, jump to write; writing data:; payload write, above jump is needed for timingcmd_write_loop:public d_out_width:out pins, 8[2] side 0x5; RD = 1, WR = 0, RS = 1set data pins, this is patched depending on 8/16 bit transfersjmp y-- cmd_write_loop[1] side 0x7; RD = 1, WR = 1, RS = 1check if more to send and loop if neededmov osr, NULL[1] side 0x7; RD = 1, WR = 1, RS = 1this does the trick without jmp !OSR;jmp !OSRE flushosr[0] side 0x7; RD = 1, WR = 1, RS = 1check if data left in OSR and jump to flushing it;jmp cmd_read[0] side 0x7; RD = 1, WR = 1, RS = 1now jump to the readflushosr:; flushing the OSR of whatever is left over, in 8 bit steps;out y, 8[0] side 0x7; ---"---;jmp !OSRE flushosr[0] side 0x7; ---"---; reading datacmd_read:; read back data from the controllermov PINDIRS, NULL[0]side 0x7; RD = 1, WR = 1, RS = 1set data pins as inputjmp !x cmd_start[0] side 0x7; RD = 1, WR = 1, RS = 1if nothing to read, jump back to startcmd_read_start:; start the actual reading if we have toout y, 32[0] side 0x7; RD = 1, WR = 1, RS = 1load numreads into yjmp y-- cmd_read_loop[0] side 0x7; RD = 1, WR = 1, RS = 1if more than 0 to read, do itjmp cmd_start[0] side 0x7; RD = 1, WR = 1, RS = 1... but if not, back to start; reading is slow, so we need delay loops here on the RD signalcmd_read_loop:set x, 16[2] side 0x3; RD = 0, WR = 1, RS = 1prepare for RD low delay loopcmd_rdlow:jmp x-- cmd_rdlow[2] side 0x3; RD = 0, WR = 1, RS = 1loop until delay is donepublic d_in_width:in pins, 8[0] side 0x3; RD = 0, WR = 1, RS = 1read in the data at the pinsset x, 2[2] side 0x7; RD = 1, WR = 1, RS = 1prepare for RD high delay loopcmd_rdhigh:jmp x-- cmd_rdhigh[2] side 0x7; RD = 1, WR = 1, RS = 1loop until delay is donepush IFFULL BLOCK[0] side 0x7; RD = 1, WR = 1, RS = 1push data out if ISR is fulljmp y-- cmd_read_loop[0] side 0x7; RD = 1, WR = 1, RS = 1repeat reading until expected count.wrap
In any case, am i doing something wrong, or is this really some unclear documentation? I would not expect the PIO to autopull a new word as long as the OSR was not emptied (to the given threshold) if the MOV OSR... just marks it as full.
Don't get me wrong, it's great that it behaves as it does, saving the precious PIO memory! Just maybe a little mention, or some footnote, regarding the combination of autopull and MOV OSR...?
Greetings,
Chris
Statistics: Posted by mamalala — Mon Feb 10, 2025 12:29 am — Replies 1 — Views 46