orangecrab-fpga / orangecrab-examples

Example projects/code for the OrangeCrab
MIT License
104 stars 27 forks source link

[Clarification] USB questions #26

Closed francis2tm closed 2 years ago

francis2tm commented 2 years ago

Hey, I have some questions regarding the USB, specially because I saw the orange crab bootloader SoC (https://github.com/gregdavill/foboot/tree/OrangeCrab) and there the USB is added "differently" In these lines I see that you attach the USB into a seperate CSR Bus. 1) Why is it necessary? In the bootloader this isn't the case, and is the fact that the USB is attached to a sperate CSR BUS why a new csr header file (usb_csr.h) is created?

2) Why does the USB need to be in a CSR bus that's decoupled from our CPU clock? Taking into consideration that in the bootloader SoC this does not happen

In this line the USB interrupt is added (I think). In the bootloader, there is not an explicit USB interrupt addition like this, because I think this is done in the platform.finalize(). However, in the CircuitPython example, there is no platform.finalize().

3) Why did you add this line and why isn't the platform.finalize() called in this example when the bootloader does?

gregdavill commented 2 years ago

Hi! I assume you're comparing the LiteX CircuitPython SoC, and the foboot bootloader.

Why is it necessary? In the bootloader this isn't the case, and is the fact that the USB is attached to a sperate CSR BUS why a new csr header file (usb_csr.h) is created?

The main reason is that ValentyUSB expects to operate entirely in a 12MHz clock domain. This is fine if you also want to run your main processor at 12MHz. This is how we operate in the Bootloader.

For the circuit python SoC we operate the CPU at 48MHz, we could probably also run it faster.

In order to run these two parts of the design at different speeds we need a point at which we can decouple them, and then use elements that handle passing data across clock domains. I chose to do this at the wishbone interface, so this is why we create a second CSR bank. LiteX isn't really setup to automatically output register mapping for multiple CSR banks, hence the extra usb_csr.h file.

Why does the USB need to be in a CSR bus that's decoupled from our CPU clock? Taking into consideration that in the bootloader SoC this does not happen If you're okay running the CPU clock at 12MHz then it's not required.

Why did you add this line and why isn't the platform.finalize() called in this example when the bootloader does?

The finalize call in the bootloader really justs performs some final packaging that's different from the ice40, you can see the function here: https://github.com/gregdavill/foboot/blob/ab25c1542e7ccc5d70c4e7b17f7e9d1d565ae3ee/hw/rtl/platform/orangecrab.py#L137-L175

It's been a little while, but I actually don't think the bootloader uses a USB interrupt in it's firmware. So it was never connected up in gateware. It simply polls the USB core status in a while loop. This works because it's not really doing much else.

francis2tm commented 2 years ago

Thanks for the reply, Yes I'm comparing the LiteX CircuitPython SoC, and the foboot bootloader. It makes sense! And regarding the CPU interrupt connection, I did a mistake and I was actually referring to the function soc.finalize() and not platform.finalize(). In the bootloader, the soc.finalize() is called here: https://github.com/gregdavill/foboot/blob/ab25c1542e7ccc5d70c4e7b17f7e9d1d565ae3ee/hw/foboot-bitstream.py#L345 . According to litex source, soc.finalize() performs the cpu interrupt connection ( https://github.com/enjoy-digital/litex/blob/3c3884b1ea545905b9cf20cd2682400f95f1bcd3/litex/soc/integration/soc.py#L1102-L1120)

For this reason, my question is:

Why did you do an explicit self.comb += self.cpu.interrupt[self.interrupt_map['usb']].eq(self.usb0.irq) in the CircuitPython SoC when (I think) this could've been achieved with the soc.finalize(), which is not called in the CircuitPython SoC?

gregdavill commented 2 years ago

I think I got it working, then just left it.

To get LiteX to auto connect the line you'd probably just need to create a Event Wrapper shell. Since that's where it's expecting the IRQ line to be.

francis2tm commented 2 years ago

Ok, makes sense, thanks for the info!