I'm trying to send input from the firmware to the ...
# mpw-6plus-silicon
m
I'm trying to send input from the firmware to the user_project. From the mprj_stimulus testbench, it seems it's possible by first setting the pin as an input, then doing the reg_mprj_xfer, then setting them to management outputs. (note that the mprj_stimulus fw seems wrong because the comment says it will "recast" the channels to allow input, but they original setup for the channels is not input but mgmt output: <https://github.com/efabless/caravel_user_project/blob/d9ddc78b65db1d5f8c2871925cdec26bf95b5d53/verilog/dv/mprj_stimulus/mprj_stimulus.c#L87>. Has anyone managed this? While doing this, I've hit another issue. If I'm doing individual bit sets and clears on reg_mprj_data it seems to wipe the whole reg. My workaround is to do all the bit manipulation on a temp register and then copy that to the reg_mprj_data register.
Here's how I'm setting up the inputs:
And then driving:
this sequence works if I drive pins 33, 35 & 37 and then use jumper wires to connect 33->32, 35->34 and 37->36
I'm just trying to do it without the jumpers
t
The trick with doing a transfer and then setting the registers differently afterward only applied to Caravel chips up to MPW-5. For the newer design, it became clear that the distance from the processor to the GPIOs was too long for a single bidirectional wire (because it can't be buffered in both directions), so we switched to two dedicated wires between the management processor and each GPIO (one in, one out). So it's possible to read from and write to each GPIO at the same time.
m
can you give me a code example of how to drive a user input pin from the managment fw?
also - do you know why the bit set / clr doesn't work?
t
How do you have CLR and SET defined?
m
image.png
t
Hmmm. . . I think that switching the definition from USER to MGMT after the serial transfer like you did may still be the correct way to do it.
m
They work as expected on an unsigned int.
t
I wonder if there is an issue with using expressions like
|=
and
&=
; that implies a memory read followed immediately by a memory write. I will stare at the housekeeping code a bit---the housekeeping GPIO access is a little awkward because it shares the registers between the wishbone and SPI interfaces, and so it does all 32-bit reads and writes as four separate 8-bit reads and writes, which might have something to do with the phenomenon you're seeing. Meanwhile, does it work if you replace the expression with a separated read and write?---
#define SET(PIN,N) (PIN = PIN | (1<<N))
or
#define SET(PIN,N) (temp = PIN; PIN = temp | (1<<N))
?
m
I can test that easily
would you expect an input pin that was being written to by the fw to actually toggle on the pin of the chip?
t
Yes, it would actually toggle on the pin of the chip. What I think you want to do differently is to just set
reg_mprj_io_32/34/36
to
GPIO_MODE_MGMT_STD_OUTPUT
to begin with. The user project will be able to read the value regardless.
m
#define SET(PIN,N) (PIN = PIN | (1<<N))
doesn't work. as soon as the next set happens it clears all other bits
t
Is that true for
reg_mprj_datah
only, or is it also true for
reg_mprj_datal
?
m
the other suggestion causes compilation errors
image.png
same issue on reg_mprj_datal
t
Oh, it would have to be
#define SET(PIN,N) temp = PIN; PIN = temp | (1<<N)
without the outer parentheses around the expression. Or maybe
#define SET(PIN,N) {int temp = PIN; PIN = temp | (1<<N)}
(which may be better as it allows the variable
temp
to be defined within the context of the definition).
m
nearly - needed one final ; before the }
t
Right.
m
still doesn't work though
as soon as the next SET is called it wipes out any bits that were already high
which I don't understand at all
as it's now basically what I was doing before on multiple lines
t
I'm thinking it might make sense if the wishbone acknowledge signal is being set too early so that it returns control to the processor before the housekeeping state machine has finished processing the data. But that will take some investigation.
m
actually what I was doing was never reading from register, doing all the manipulations on temp and then just copying it over
t
But the
|=
expression implies a read followed by a write.
m
I think you might be right. I have definitely witnessed some weird wishbone stuff when working on the cocotb testbenches. Like, unless you have a delay in between wishbone writes then they can get lost.
image.png
first one doesn't work, second does
obviously only any good if nothing else is changing the reg inbetween
but still makes my code neater
your suggestion on setting to the pins to MGMT OUTPUT doesn't work unfortunately
the pins toggle on the outside of the chip, but the value doesn't get to the user design
t
Whoops, input buffer has to be turned on. Use
GPIO_MODE_MGMT_STD_BIDIRECTIONAL
(make sure it's defined as
0x1801
).
m
that works!
thanks!
t
Tentatively, the reason that
|=
doesn't work is that the GPIO data read value is not equal to the GPIO data write value. I think that
STD_BIDIRECTIONAL
must be set on all channels for this to work. Because the read value is the value at the pad. If the pad input buffer is turned off (by using
STD_OUTPUT
), then it will read back zero. This should probably be better explained in documentation (also, it might be a good idea to change the implementation so that when the input buffer is off, the register value will be read back instead of the pad value. Or have an additional bit to toggle between reading from the pad vs. reading from the register value).
If you want to experiment with that, I think you should just be able to set
GPIO_MODE_MGMT_STD_BIDIRECTIONAL
on all the GPIO pads you're trying to set from the management side, and then the original expression with
reg_mprj_datal |= ...
should work like you expect.