-
Notifications
You must be signed in to change notification settings - Fork 228
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
neorv32_twi_start_trans() does not work with prsc>1 #332
Comments
Hey Andreas, you need to generate a start conditions first before you can do actual TWI transfers. So you need to call /* write to I2C */
neorv32_twi_generate_start(); // generate START conditions before triggering actual transfers
neorv32_twi_start_trans(0x55);
neorv32_twi_generate_stop(); I just had a quick look at the TWI documentation - and it seems like the documentation is not really clear here. I need to fix that! 😉 |
I just realized I mixed up |
First things first: the TWI controller works as expected on real hardware. This is a great example of a hardware-vs-simulation mismatch due to the lack of a dedicate hardware reset (a related problem is described in #330). The TWI module uses bit 31 of the status and control register to indicate a "BUSY" state. For example, this bis is set when generating a START condition (like in your example). The according C functions polls the busy bit to find out when the START condition has been successfully generated. Now the problem: bit 30 of the TWI control and status register contains the state of the last ACK/NACK that has been received. This bit is undefined as there has not been any ACK/NACK yet plus the source register of this signal has no defined hardware reset. The CPU fetches the whole 32-bit of the status and control register into some register in the CPU's register file for further inspection. The check in the polling loop evaluates to a "branch if less than zero" as the compiler is smart enough to see that the busy flag is basically the sign bit of a 32-bit value. The according VHDL comparison in the CPU is: cmp(cmp_less_c) <= '1' when (signed(cmp_opx) < signed(cmp_opy)) else '0'; -- signed or unsigned comparison As bit 30 is undefined this piece of VHDL code returns an incorrect result making the program abort the polling loop - falsely assuming that the busy flag has cleared. In summary, this messes up the TWI transaction.
In contrast, this works fine as the compiler will use a "branch if zero" instruction here using a different piece of VHDL code: cmp(cmp_equal_c) <= '1' when (rs1_i = rs2_i) else '0'; In this situation, this code returns the correct result making the polling work fine. |
Hi Stephan, thanks for your explanation. What could be the solution, providing a HW reset into the HDL sources, or using the SW workaround snippet? Thanks for you support! BR, |
Your fix is a great workaround for now, but I think a dedicated hardware reset for all IO/peripheral devices would be a better and permanent solution. Otherwise we might get trouble with this again in other places. I think I'll start working on that reset issue on another branch. Then you can have a look, too, and we can make sure to eliminate all those hardware-vs-simulation mismatch issues. |
Hi Stephan, it works with #334 ! Thanks for the really fast providing the fix /* write to I2C */
neorv32_twi_start_trans(0x55);
neorv32_twi_generate_stop(); the belonging waveform with global reset BR, |
Great to hear! You have used the modified version from #334, right? |
yes #334 was used |
Hi Stephan,
at the moment i do some tests with the TWI. My belonging C code looks like follows:
For asserting the transfer i use the NEORV32 function neorv32_twi_start_trans. For small prescaler values like 1 works this very well.
PRSC=1:
For PRSC=4 is only the starbit sended and then happends nothing
I did some investigation, the issue seems like follows, if a higher PRSC value is used, then is the FSM in the startbit state arbiter=101 and the write of ths address - in my case 0x55 - is skipped:
One possible solution could be to poll the busy flag, this would lead to an change in neorv32_twi_start_trans() and the IRQ driven I2C would not work anymore.
What are your thoughts?
BR,
Andreas
The text was updated successfully, but these errors were encountered: