USB and SPI at same time?

I can not connect to the M7 cam while it is connected to our SPI port on our NI RoboRio.

Can these 2 things be used in tandem?

Thanks
Jim

FRC 3959 SW Mentor

Yes, they both can be used at the same time. If things are not working you are causing some sort of short.

It’s sort of working, I found a power jumper on our board that may have been affecting this. It now randomly disconnects from the IDE and won’t reconnect without disconnecting and reconnecting the USB.

gnd, CS, clk, MISO, and MOSI are all connected.

We are using (in the master code) 1MHz bus speed, MSB is First, Sample on Leading Edge, clk is active high, cs is active low.

We are trying to use the SPI slave example with our NI roboRio.

I’m just getting random data. On occasion, I would see the 85 sync flag, but something has happened and I can’t see that anymore.

Please help.

Thanks
Jim

Okay, does the camera work fine when there’s no physical connection between the two devices but the SPI code is running on the camera? Also, async serial is much easier to get working on the OpenMV Cam and another device versus SPI.

With the SPI wires disconnected, it does nothing except say “Waiting for Arduino”.

Here is the code, we have modified it a little to debug.

Trying to look at our buffer on the master, it just looks like garbage. I started off reading 18 bytes and changed to 25. Got worse. I haven’t done SPI in 15years. So I’m a little rusty.

Thanks
Jim
arduino_spi_slave_1.py (4.68 KB)

Hi, I don’t really have time anymore to debug code like this. If you ask me a clarification question about a line I can help but just giving me a giant code dump is not something I’m able to work on anymore. Um, it’s FAR easier just to get async serial working to the Arduino.

Use the SoftwareSerial library on the Arduino: https://www.arduino.cc/en/Reference/softwareSerial - Make the baud rate something low. And then just use the UART functionality of the OpenMV Cam to send data. This is so much easier and requires less wires.

I’m really sorry if you felt like I was abusing your time. I appreciate the help. I didn’t intend for you to try to run the file.

We aren’t using Arduino. We are using a Linux based system from National Instruments called a RoboRio (Rio for short). If we were using Arduino, your example with the master code would have been extremely easy to get working. UART on our system is not ideal for our needs. We are trying to reach some really high cycle times with our vision system (around 15ms, our main control loop is running at 5ms), so we need to use a faster protocol. Shooting for 1Mhz or more. I’m thinking I will setup a IO line from the M7 to the Rio to trigger an interrupt thread to pull the data. The Rio can’t act as a slave.

Does the M7 have to wait in code for the CS to be driven or can a thread be created to manage the SPI communication so the main task of image processing can continue?

Thanks again.
Jim

So I’ve made progress. But something is screwed up. If I read more than my buffer contains, it seems to really screw up the M7 camera. I rarely can get the message. I’ve gone back to only trying to pull the 24 bytes, and that plus removing the while loops in your example and rapping the try/catch in an if that looks for the pin to go low seems to fix the issue mostly. However I will get a lot of garbage data on the first few reads and every 25 or more reads. Is there something I’m missing?

This is a lot easier to play with when my students aren’t around. again, sorry for yesterday, I had a ton of students bothering me with everything from CAD, 3D printers, and all sorts of SW stuff.

Ah, okay, um, getting SPI working is not impossible. I’m not sure what the issues you are having is however.

Okay, um, let me give you a simple script idea that should put you on the right track.

Oh, we will have a CAN shield in stock too for that system. You’re doing FIRST right?

Yes we are the FRC team that you donated 2 boards to. CAN would also be amazing. Do you have a FRC library for it?

I think I got SPI working by removing the while loops in your example and only reading the 24 bytes. However, that is all I can do in the scrip if I want to read the “Hello World” message. I’m currently trying to use the ISR functionality. Am I on the right track here? I’m no python expert, been picking it up for this.

ARRAYSIZE = const(24)
txdata = array.array('b', 0 for x in range(ARRAYSIZE))
msgId = 0

def spi_ISR()
    global spi, txdata
    spi.send(txdata, timeout=100)
    blue_led.toggle()
    
def UpdateBuf(data)
    irq_state = pyb.disable_irq()
    txdata = ustruct.pack("<bi%ds" % len(data), 85, msgId, data) # 85 is a sync char.
    txdata += "\x00" * (24 - len(data))
    msgId += 1
    pyb.enable_irq(irq_state)

spi = pyb.SPI(2, pyb.SPI.SLAVE, polarity=0, phase=0)
pin = pyb.Pin("P3", pyb.Pin.IN, pull=pyb.Pin.PULL_UP)
pin.irq(handler = spi_ISR, trigger = Pin.IRQ_FALLING)

Um, the CAN boards are not out yet but I should get them at home to test soon. I can provide I think 2 once I get them.

Sorry about this all being hard. If you could just use the UART this is very easy.

Anyway, what you have is exactly what you want to do actually. If you could make the OpenMV Cam the SPI master that would be better. But, what you have done is basically the best you can do. If you need to handle errors add try: except: blocks around the lines that might fail. The pyb module throws an exception on any timeouts and etc.

Given your code above then just update the buffer in a loop and you are good.

I wish we could make the Rio a slave. If I knew more on how the SPI driver worked, this probably would have been a lot easier.

So far, what I’ve learned is that if you are not bit banging your CS line and using built in hardware, you don’t want to use your while(high) pass; spi transaction; while( low) pass. With your example, because the Arduino is so slow relative to the M7 (16MHz vs 216MHz) you can wait for the CS to go low, transmit, and then wait for the CS to return high. On a system running 667MHz, the first while(high) loop would hold up the logic to the point where we would have to initiate 2 spi transactions (at 1MHz) to get any data. It also seems to run way better when the IDE is not active. Are you sure there are no shared resources between the SPI memory Segment and whatever the IDE uses? I would get some pretty crazy data occasionally and if we initiated a high frequency of spi transactions, the IDE would lose connection with the board.

Maybe we can spearhead this as another example you could include that would demonstrate a drop in solution for SPI Slave, ISRs, and shared memory. We would be glad to try the CAN boards too. We are going to make the code we develop as clean as possible so that we can share the code with other teams and they will just need to buy your camera.

I’ll update you tonight on how this ISR code works out.

Thanks
Jim

Hi, what you are seeing is that when you disable interrupts you starve the USB from working correctly causing issues with the IDE. USB is firing every millisecond (or 8x that) so you have to complete your SPI transactions quickly. Basically, there’s a lot going on behind the scenes that gets interrupted whenever you disable interrupts.

Is it a safe assumption that this happens if you do not disable the interrupts because the interrupts are disabled while SPI is doing a transaction?

So, how many bytes are you sending via SPI at 1 MHz? How long is this in time? For an example, if you use our LCD shield this sends data via SPI. But, you can use it at the same time as the USB from OpenMV IDE.

The general issue is that you’re in an interrupt handler sending SPI data. In our SPI code a DMA handle is used to transmit more than 1 byte and the processor just waits with interrupts enabled for the transaction to finish. In your code the processor can’t be interrupted while sending the data.

Anyway, I just got the CAN shield in. I will get it debugged and working ASAP.

a transaction is 20 bytes. We would like to have a transaction every 15ms.

What should I be doing in my ISR to do this properly?

I’ve got SPI working I think, but now we are not getting the main loop body to run in time. We have to read SPI from master 6 times to see a change in data from our main loop body. I’m at a loss as to what I’m doing wrong. It does seem that if I remove instructions from my main body, it requires less SPI reads to see data change. I’m attaching our code, if you have time to look at it.

The code is:
SPI_ISR:
Build tx buffer
Send tx buffer

Main Body Loop
take image
Line = Linear regression alg
disable interrupts
Update loop time, increment variable, decrement different variable
enable interrupts
spi_slave_Line_ISR.py (4.63 KB)

Hi, I honestly don’t really know how to get the SPI code working. SPI is really only to be used not in an interrupt. The OpenMV Cam isn’t designed to be a slave processor. It’s built to be a master. So, using it as a slave SPI or I2C device doesn’t really work.

Anyway, I got my CAN shields back and they appear to be working. I got CAN transmit and receive operational at 1 Mb/s. I can send you two shields. As for examples, I will be writing up some stuff Monday and I’ll have some full feature scripts that show transmit and receive at multiple baud rates along with message filtering and etc. CAN is and UART are the way to go to network the OpenMV Cam with other processors. I also got my RS232 shield back too. On both boards I messed up some stuff and have to do another prototype run. However, the CAN shield is functional after removing one component where I put the wrong part.

Please email me with your address and I will send you two boards via FedEx.

I just sent you an email with my info. Thank you so much for all your support and sponsorship of our High School Robotics Team.

We will fall back to UART until we receive the CAN shields. Maybe we will get lucky and UART will be fast enough.

Thanks So much. WE ARE VERY GRATEFUL!!!

Jim