Question: May I write a program for Caravel to tes...
# gf180mcu
a
Question: May I write a program for Caravel to test the design - set inputs and read outputs programmatically?
t
Yes. Do you have all the information you need for writing and running a test program?
a
I see blink example that programs all IOs as outputs but it's not clear for me how to control IOs for debugging embedded user design
t
Tell me how you want to set up the interface for testing, and I can help you with what your test program needs to do.
a
I have user defines like this:
Copy code
`define USER_CONFIG_GPIO_5_INIT `GPIO_MODE_USER_STD_INPUT_PULLDOWN
`define USER_CONFIG_GPIO_6_INIT `GPIO_MODE_USER_STD_INPUT_PULLDOWN
`define USER_CONFIG_GPIO_7_INIT `GPIO_MODE_USER_STD_INPUT_PULLDOWN
`define USER_CONFIG_GPIO_8_INIT `GPIO_MODE_USER_STD_INPUT_NOPULL
`define USER_CONFIG_GPIO_9_INIT `GPIO_MODE_USER_STD_INPUT_NOPULL
`define USER_CONFIG_GPIO_10_INIT `GPIO_MODE_USER_STD_INPUT_NOPULL
`define USER_CONFIG_GPIO_11_INIT `GPIO_MODE_USER_STD_INPUT_NOPULL
`define USER_CONFIG_GPIO_12_INIT `GPIO_MODE_USER_STD_INPUT_NOPULL
`define USER_CONFIG_GPIO_13_INIT `GPIO_MODE_USER_STD_INPUT_NOPULL
`define USER_CONFIG_GPIO_14_INIT `GPIO_MODE_USER_STD_INPUT_NOPULL
`define USER_CONFIG_GPIO_15_INIT `GPIO_MODE_USER_STD_INPUT_NOPULL
`define USER_CONFIG_GPIO_16_INIT `GPIO_MODE_USER_STD_INPUT_NOPULL
`define USER_CONFIG_GPIO_17_INIT `GPIO_MODE_USER_STD_INPUT_NOPULL
`define USER_CONFIG_GPIO_18_INIT `GPIO_MODE_USER_STD_INPUT_NOPULL
`define USER_CONFIG_GPIO_19_INIT `GPIO_MODE_USER_STD_INPUT_NOPULL
`define USER_CONFIG_GPIO_20_INIT `GPIO_MODE_USER_STD_INPUT_NOPULL
`define USER_CONFIG_GPIO_21_INIT `GPIO_MODE_USER_STD_INPUT_NOPULL
`define USER_CONFIG_GPIO_22_INIT `GPIO_MODE_USER_STD_INPUT_NOPULL
`define USER_CONFIG_GPIO_23_INIT `GPIO_MODE_USER_STD_INPUT_NOPULL
`define USER_CONFIG_GPIO_24_INIT `GPIO_MODE_USER_STD_OUTPUT
`define USER_CONFIG_GPIO_25_INIT `GPIO_MODE_USER_STD_OUTPUT
`define USER_CONFIG_GPIO_26_INIT `GPIO_MODE_USER_STD_OUTPUT
`define USER_CONFIG_GPIO_27_INIT `GPIO_MODE_USER_STD_OUTPUT
`define USER_CONFIG_GPIO_28_INIT `GPIO_MODE_USER_STD_OUTPUT
`define USER_CONFIG_GPIO_29_INIT `GPIO_MODE_USER_STD_OUTPUT
`define USER_CONFIG_GPIO_30_INIT `GPIO_MODE_USER_STD_OUTPUT
`define USER_CONFIG_GPIO_31_INIT `GPIO_MODE_USER_STD_OUTPUT
`define USER_CONFIG_GPIO_32_INIT `GPIO_MODE_USER_STD_OUTPUT
`define USER_CONFIG_GPIO_33_INIT `GPIO_MODE_USER_STD_OUTPUT
`define USER_CONFIG_GPIO_34_INIT `GPIO_MODE_USER_STD_OUTPUT
`define USER_CONFIG_GPIO_35_INIT `GPIO_MODE_USER_STD_OUTPUT
`define USER_CONFIG_GPIO_36_INIT `GPIO_MODE_USER_STD_INPUT_PULLDOWN
`define USER_CONFIG_GPIO_37_INIT `GPIO_MODE_USER_STD_INPUT_PULLDOWN
So IOs 8 to 23 are inputs and IOs 24 to 35 are outputs - I want to be able to write values to inputs and read outputs programmatically
t
The 38 GPIOs are mapped into two registers called
reg_mprj_datal
and
reg_mprj_datah
. GPIO 0 is the low bit of
reg_mprj_datal
up to GPIO 31, which is the high bit of the (32-bit) register. Then GPIO 32 is the low bit of
reg_mprj_datah
up to GPIO 37, which is the 6th bit. You can read or write GPIOs simply by doing
Copy code
reg_mprj_datal = value
or
Copy code
value = reg_mprj_datal
Reading a single GPIO is just a matter of bit-masking the value:
Copy code
gpio8_value = (reg_mprj_datal >> 8) & 1;
Just be aware that every time you access the register, you get the values at the time of the access. There are some restrictions on simultaneous access, such as that GPIOs 32 to 37 cannot be read (or written) at the exact same time as GPIOs 0 to 31 because you can only do 32-bit register accesses.
a
Should I reprogram IOs in any way similar to blink demo does? Or just read and write as is?
t
The blinking is done on the LED connected to the "management GPIO", which is a single GPIO pin used exclusively by the management SoC. That one pin gets configured completely differently than all the others. But you do need to run the I/O configuration subroutine, and that should be followed by setting the I/O configuration values in housekeeping (since the configuration subroutine uses a method that bypasses the housekeeping configuration).
a
Ok, so what exactly should I do to write to user module inputs and read from user module outputs?
t
I'm unsure of what your environment is. You're trying to write a program to run in a verilog testbench to test the chip at the top level? Are you applying user inputs from off chip and want to know how to apply those values from a verilog testbench?
a
No, I want to use on-board Caravel to test user design located in the same chip - nothing external
t
If this is a design still in progress, I would suggest using the "logic analyzer" interface to do input and output directly between the management SoC and the user project, and use the logic analyzer "oeb" lines to control which source (pin or logic analyzer) is input to the user project. If this is a completed design and there are only pin inputs to the user project, then there was a discussion recently about how to set up the GPIO to write values from the management SoC to the pin and have them read by the user project, and vice versa. Let me look it up.
a
What is the difference between completed design and “still in progress” design? It’s just a test so I guess any possible way is good at this point.
I have 16 inputs and 12 outputs in my user project so using a single GPIO is not enough I guess
t
I was wondering if this was a test for a design that you had already submitted, so that changing the design itself was not an option. So this is a design in progress; that makes it pretty easy. There are two good choices: (1) Drive input and output through the logic analyzer like I described above, so that the logic analyzer can replace all the chip inputs when turned on. Then you can create any stimulus to your user project that you want by setting the appropriate logic analyzer bits. Reading values back from the user project is even easier, because you just need to connect each signal to both the pin and a logic analyzer input. (2) You can use the management SoC to drive pins that are inputs of the user project, and read pin values that are outputs of the user project. To do this, you need to set the GPIO configurations twice: First, you set all the GPIO configurations appropriately for the user project, and program those values into the GPIO (applying the transfer bit). Then, you rewrite all the GPIO configurations appropriately for the management SoC (so the user-controlled inputs become management-controlled outputs, and the user-controlled outputs become management-controlled inputs). But don't program those values into the GPIO (that is, don't apply the transfer bit again). Then the management SoC can write to pins that are being read by the user project, and it can read pins that are being written to by the user project.
a
What is a transfer bit? I thought user project setup IOs according to user defines (see above) - should it be repeated from the program as well? Or program should setup all IOs as management controlled IOs since the beginning?
t
Programming I/Os is a 2-step process. The configuration values are kept in registers close to each GPIO, but to prevent having hundreds of wires going up the sides of the chip, the values are duplicated in the housekeeping module and transferred to the location near the GPIO using a simple serial shift register. The shift register programming is mostly automatic but you start it by writing to a "transfer bit" in the memory map (
reg_mprj_xfer = 1
is how you do it from C code). The configuration values near the GPIO are how the GPIO gets its own configuration. The values in housekeeping are what the management SoC think the GPIOs are configured to. So the trick here is to get the management SoC to think that the GPIOs are different from what they actually are. Although one thing I said was wrong; if you want the management SoC to drive a pin and the user project to read that pin, then the GPIO needs to be configured as a management-controlled output, not a user-controlled input.
Probably a bit of example code is worth more than a long description of the problem.
a
Ok, I’ll try, thanks
Apparently nothing is working - tried to set inputs and outputs as per user projects "user defines" and to do "transfer bit", then tried set mgmt outputs for inputs and mgmt inputs for outputs without "transfer bit", then tried setting up the same with "transfer bit" - no readings from user project - it's always zeros...
now I see some differences- not zeros anymore
so at least it's reading something
no, it's actually values from user inputs
and they are different from what program writes there...
a
@Tim Edwards @Alexander Shabarshin one quirk that I ran into was that the IO config had to be set such that both IE and OE are set
Copy code
// mgmt_en = 1, oe_ovr = 1, ie = 1, oe = 1
// all other cfg bits = 0
#define MPRJ_INPUT_CFG 0x00F

// mgmt_en = 0, oe_ovr = 1, ie = 1, oe = 1
// all other cfg bits = 0
#define MPRJ_OUTPUT_CFG 0x00E
after setting it up this way and then doing the mprj_xfer, i was able to get both directions (caravel writing to user project inputs, and reading from the user project outputs) working. one quirk is that the user project inputs being overridden by caravel do actually drive the physical pin as well, so nothing else can be connected/driving that
image.png
a
Hm, so it's not pre-existing macros, but new bitsets?
a
yep
at least that's the only way i was able to get it to work for my setup
a
might it be some kind of forbidden bit combinations? like if you write 32 bits it may drive some bidirectional IOs that already getting outputs from user project so it might be a short circuit if one part drive it zero and another to one, no?
a
i believe it shouldn't be possible to create any forbidden states, at least with these configs
image.png
this is what the I/O cell looks like, and anything on the left side is all synthesized digital signals which shouldn't be possible to ever have a multi-driver scenario
image.png
this is how the pad is interfaced to the mgmt/user sections - its all digital MUXes
i think if you have bidirectional stuff in your user-project you might not be able to use it with this setup though
because something that's bidirectional from the user project's side would mean that the "is this controlled by management or the user project" would depend on whether your user project has enabled the output or not
but the management core is the one that gets to choose whether something's controlled by management or user project, so its a bit of a catch-22
still shouldn't be possible to short anything out, but wouldn't give you the desired behavior either
a
ok, I don't have bidirectionals so it should be good
let me try it
Yey, it works, thanks!!! 🙂