Skip to content
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

SPI: Master/Slave 16b works, but 8b does not #3

Closed
hgrodriguez opened this issue Jul 25, 2021 · 9 comments
Closed

SPI: Master/Slave 16b works, but 8b does not #3

hgrodriguez opened this issue Jul 25, 2021 · 9 comments

Comments

@hgrodriguez
Copy link

hgrodriguez commented Jul 25, 2021

Hi Jeremy,
first of all thanks a lot for your great work to implement this software which is so useful.

I was looking at your example: spi_loopback and I found the Test_Slave procedure perfectly working.
As this is implemented as 16b, I tried to implement an 8b version as an exercise for me.

(I do not have your debug setup yet, so I am stuck with a logic analyzer)
Using my logic analyzer I can confirm, that your code using 16b works. Changing this to 8b seems not working.
The code below is the bare minimum code I can offer to re-produce.
I kept all your output/pragma as comments, as I do not have the setup yet.

Again thanks for all your work.
I hope the code below (it compiles at my side without any problems) helps to identify the issue.

Regards,
Holger

PS: I tried to insert the code below as code, but somehow I do not get it. Sorry for this, you may have to reformat on your side :-(

============================================

with HAL;
with HAL.SPI;

with RP.Clock;
with RP.GPIO;
with RP.SPI;
with RP.Device;

with Pico;
with Board;

procedure Main_TestSlave_16_8 is

procedure Test_Slave_16
(Name : String;
Master_Config : RP.SPI.SPI_Configuration;
Slave_Config : RP.SPI.SPI_Configuration)
is
-- Things need to happen in the following order:
-- 1. Set A := I, B := not I
-- 2. Put A in the slave's transmit FIFO
-- 3. Transmit B from the master to generate a clock
-- 4. Read A from the master FIFO into B, check A = B
-- 5. Read B from the slave FIFO into A, check A = not B
A : HAL.SPI.SPI_Data_16b (1 .. 1) := (others => 0);
B : HAL.SPI.SPI_Data_16b (1 .. 1) := (others => 0);
Status : HAL.SPI.SPI_Status;
use HAL;
begin
-- Ada.Text_IO.Put (Name & "...");
Board.SPI_Master.Configure (Master_Config);
Board.SPI_Slave.Configure (Slave_Config);

  --  Slave to master
  for I in 1 .. 1 loop
     A (1) := HAL.UInt16 (16#5A5A#);
     B (1) := not A (1);

     Board.SPI_Slave.Transmit (A, Status);
     --  pragma Assert (Status = Ok, "Slave transmit: " & Status'Image);
     
     Board.SPI_Master.Transmit (B, Status);
     --  pragma Assert (Status = Ok, "Master transmit: " & Status'Image);

     Board.SPI_Master.Receive (B, Status);
     --  pragma Assert (Status = Ok, "Master receive: " & Status'Image);
     --  pragma Assert (A = B, "Master received incorrect value: " &
     --                   "A = " & A (1)'Image & ", " &
     --                   "B = " & B (1)'Image);

     Board.SPI_Slave.Receive (A, Status);
     --  pragma Assert (Status = Ok, "Slave receive: " & Status'Image);
     --  pragma Assert (A (1) = not B (1));
  end loop;
  --      Ada.Text_IO.Put_Line ("PASS");

end Test_Slave_16;

procedure Test_Slave_8
(Name : String;
Master_Config : RP.SPI.SPI_Configuration;
Slave_Config : RP.SPI.SPI_Configuration)
is
-- Things need to happen in the following order:
-- 1. Set A := I, B := not I
-- 2. Put A in the slave's transmit FIFO
-- 3. Transmit B from the master to generate a clock
-- 4. Read A from the master FIFO into B, check A = B
-- 5. Read B from the slave FIFO into A, check A = not B
A : HAL.SPI.SPI_Data_8b (1 .. 1) := (others => 0);
B : HAL.SPI.SPI_Data_8b (1 .. 1) := (others => 0);
Status : HAL.SPI.SPI_Status;
use HAL;
begin
-- Ada.Text_IO.Put (Name & "...");
Board.SPI_Master.Configure (Master_Config);
Board.SPI_Slave.Configure (Slave_Config);

  --  Slave to master
  for I in 1 .. 1 loop
     A (1) := HAL.UInt8 (16#5A#);
     B (1) := not A (1);

     Board.SPI_Slave.Transmit (A, Status);
     --  pragma Assert (Status = Ok, "Slave transmit: " & Status'Image);
     
     Board.SPI_Master.Transmit (B, Status);
     --  pragma Assert (Status = Ok, "Master transmit: " & Status'Image);

     Board.SPI_Master.Receive (B, Status);
     --  pragma Assert (Status = Ok, "Master receive: " & Status'Image);
     --  pragma Assert (A = B, "Master received incorrect value: " &
     --                   "A = " & A (1)'Image & ", " &
     --                   "B = " & B (1)'Image);

     Board.SPI_Slave.Receive (A, Status);
     --  pragma Assert (Status = Ok, "Slave receive: " & Status'Image);
     --  pragma Assert (A (1) = not B (1));
  end loop;
  --  Ada.Text_IO.Put_Line ("PASS");

end Test_Slave_8;

begin
RP.Clock.Initialize (Pico.XOSC_Frequency);
RP.Device.Timer.Enable;
Pico.LED.Configure (RP.GPIO.Output);

Board.Initialize;

loop
if True then
Test_Slave_16 ("Slave transmit 16b",
Master_Config =>
(Role => RP.SPI.Master,
Baud => 10_000_000,
Data_Size => HAL.SPI.Data_Size_16b,
others => <>),
Slave_Config =>
(Role => RP.SPI.Slave,
Baud => 10_000_000,
Data_Size => HAL.SPI.Data_Size_16b,
others => <>));
else
Test_Slave_8 ("Slave transmit 8b",
Master_Config =>
(Role => RP.SPI.Master,
Baud => 10_000_000,
Data_Size => HAL.SPI.Data_Size_8b,
others => <>),
Slave_Config =>
(Role => RP.SPI.Slave,
Baud => 10_000_000,
Data_Size => HAL.SPI.Data_Size_8b,
others => <>));
end if;
Pico.LED.Toggle;
end loop;

end Main_TestSlave_16_8;

@JeremyGrosser
Copy link
Owner

If it's just stopping and not producing any more output, it's likely that an exception has been raised. If you attach an SWD debugger, you should get some exception information from semihosting output. Without an SWD debugger, you're working blind.

My workbench is occupied by other projects at the moment, so I can't setup the spi_loopback demo and test this for you right now.

@JeremyGrosser
Copy link
Owner

I was able to reproduce this issue. It's hitting a timeout at Board.SPI_Slave.Transmit (A, Status);. The slave can't empty its FIFO until the master generates a clock, so it's guaranteed to always timeout if the slave is in blocking mode. If you add Blocking => False to the slave config, the test passes.

The 16-bit version of this test was incorrectly passing due to a bug in rp2040_hal. I had forgotten to add the Blocking behavior to the 16-bit version of RP.SPI.Transmit when I added it to the 8-bit procedure. I've fixed that and updated both rp2040_hal and pico_examples.

JeremyGrosser added a commit that referenced this issue Jul 26, 2021
@hgrodriguez
Copy link
Author

thanks a lot!!! I will fetch the new code and start over my experiments.

@JeremyGrosser
Copy link
Owner

Have you had a chance to test this fix?

@hgrodriguez
Copy link
Author

the last weeks in work were hell, and the next couple of weeks are not better. i will put it on my list to do with prio=1. I do not ignore you or your effort at all. just very hectic currently in my life.

@JeremyGrosser
Copy link
Owner

No problem, I just didn't want to let this issue go stale. Test it when you have time, no rush.

@hgrodriguez
Copy link
Author

i did not check yet, but did you extend your test suit for the 8bit and does it work?

@JeremyGrosser
Copy link
Owner

I did, but I hadn't committed it yet. I've just pushed the additional test to pico_examples.

@hgrodriguez
Copy link
Author

Hi Jeremy, i just checked, and I can see, that both 16b and 8b versions seem to work. Thanks for fixing this,

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants