Pi SPI under RISCOS
Jon Abbott (1421) 2597 posts |
Has anyone tried communicating over SPI under RISCOS? I’m toying with getting a Pi 2 with TFT and using it to display debugging information. There’s also the possibility of writing a GraphicsV driver for it and using it as a screen, which would be rather handy when I’m testing games under ADFFS. Having never touched I2C or SPI before, I’m not sure if it’s possible to access SPI under RISCOS. I suspect it may involve interfacing with the Pi kernel blob (if thats the correct terminology?) |
Chris Evans (457) 1614 posts |
SCI Is that a typo? should it be SDI |
Jeffrey Lee (213) 6046 posts |
Looks like it should be SPI, not SCI/SDI. There’s been discussion about writing an SPI driver module, but nothing’s come of it yet. |
Rob Wilks (2324) 6 posts |
I have been using SPI to control both an ADC (MCP3208 – 12 bit, 8-channel) and a DAC (the one on the Gertboard). This is all under RiscOS using the Broadcom registers. I prefer using Forth, but I have used Basic with some assembler calls (see an article in DragnDrop about 1 year ago (title: “Experience of the SPI bus on Raspberry Pi”). Please email me if you want any downloads. |
Chris Evans (457) 1614 posts |
Doh! Now it’s me also getting it wrong it should have said SPI. |
Jon Abbott (1421) 2597 posts |
Sorry, typo now corrected. Not sure how to correct the title though. Rob – excellent, thanks for the confirmation. I’ll order one and see how I get on. |
Jon Abbott (1421) 2597 posts |
I couldn’t find the Drag’n’Drop article on the web, is there a link to it? Some reference material I have found: BCM2835 ARM Peripherals.pdf (chapter 10) |
Bill Antonia (2466) 120 posts |
Hi. Yes managed to communicate with the ADC chip on the Gertboard. Far as I remember as I don’t have the code in front of me at the moment, I wrote a module in assembler and C code to communicate with the modules SWIs. Used a rheostat to change the input voltage. I’m going to start tinkering with a MAX7221 chip to interface with eight 7 segment displays, initially using RiscOS to do the testing of the code then transfer that to run on bare metal. Plan is to show the ADC output on the 7 segment displays. |
Bill Antonia (2466) 120 posts |
Thought I’d add a link to the download of the current state of my PiSPI module and test software. Contains full source. |
Jon Abbott (1421) 2597 posts |
Thanks Bill. Can I use that Module to write a data stream to screen in the OP? Looking at the function names it looks like you’ve probably added everything I’ll require. |
Bill Antonia (2466) 120 posts |
Currently as far as I remember It will only do polled SPI. If that’s ok, go ahead and see what you can do. I did write it last year, but did check it out before I uploaded that it was functional. If you look at the code there is plenty of room for expansion regarding SWIs. Obviously the addition of other SPI modes would be helpful. When I registered for the SWI block, Ben Avison did point out: “I’ll also draw your attention to section 1.3 of the BCM2835 ARM This is something I haven’t looked into yet as I’m not sure what is required, section 1.3 doesn’t provide any code examples. If anyone has any input to this, all to the good. Is it the addition of a few nop instructions or the equivalent? One thing though, it is specific for the BCM2835 chip, I haven’t tested on a BCM2836, ie a Raspberry Pi 2. I’ve recently collected together a variety of devices which communicate via SPI to test, however a screen was not one of them. |
Jon Abbott (1421) 2597 posts |
I’ll also draw your attention to section 1.3 of the BCM2835 ARM No problem, that neatly feeds into my suggestion about extending OS_MMUControl to expose these ARMOps to the user. In the case of the Pi, Data Memory Barrier is:
It ensures all pending memory actions are complete before attempting any more. You’d use it when swapping data pages that have potentially been written to and are about to be swapped out. Not relevant to this, but for reference, there’s also Data Synchronization Barrier (previously known as Drain Write Buffer) which is used prior to executing code that’s just been written to memory:
If you don’t mind, I’ll look at extending your Module if it’s required. I’ve yet to look at what’s involved in writing data to the screen, so at this point I’m unsure if it actually needs anything additional. I’ve have now ordered the Pi 2 and the screen and as soon as the next release of ADFFS is out the door, I’ll start work on both a GraphicsV driver to use it as a primary display (for MODEs: 1, 2, 4, 5, 9, 10, 13) and a Debug Module to use it as a secondary display for displaying realtime debug info. That will make my job a lot easier when debugging games that don’t work on the Pi, I can display the CPU instructions as they execute and it will remain should the machine lock. For the GraphicsV driver, I have a choice. I can either use the same technique ADFFS uses, where it drops RISCOS back to using DA2 for the screen, or I can create a new DA. The first method would make it backward compatible with legacy games that rely on DA2 (as virtually all do) and the later would be as GraphicsV was designed. Thinking about it, I’ll probably offer both in the Module so it can be switched between legacy MODE emulation via blits with palette conversion from DA2, or a straight 16bit screen available to GraphicsV as it was designed to be used. I’ll need to see what the performance impact is on the Pi and how long it takes to copy a frame, this will limit the frame rate and define what Hz it will appear to RISCOS as. SPI doesn’t have a very high throughput and I’d be pushing 160KB/frame for MODE 13 (8MB/sec for 50Hz). It can be done in the background via RTSupport, possibly breaking it into chunks or alternate scan lines, so the limiting factor will be the amount of time it takes to push one frame. Reading this project (and confirmed here), it looks like the data throughput limit on the Pi is 2.2MB/sec / SPI 32MHz, which will limit the refresh rate for MODE 13 to 25Hz. It also looks like the BCM2835 (and presumably the BCM2836 as well) operate in Polled mode. For reference, there’s some detail on how to get the screen working under Raspbian here |
Jeffrey Lee (213) 6046 posts |
To minimise CPU overhead it might be worth getting DMA working with the SPI driver (the hardware should support it, I believe). Then you can just DMA a full screens worth of data at a time. If you need to software convert 1/2/4/8bpp to true colour then it might be better to compare the new data against the softcopy and either just DMA the changed regions or transfer it manually using the CPU. If the SPI is limited to 2.2MB/sec then I suspect DMA will always win in terms of reducing CPU usage. |
David Feugey (2125) 2687 posts |
With support of HOMM2? :) |
Bill Antonia (2466) 120 posts |
I’ve added the DMB instructions, might as well start adding these from the beginning, instils a habit. This is version 0.02 of the module. |
Andrew Conroy (370) 724 posts |
This might be a silly question, but is there any documentation on how to use the module (even just a list of SWIs and what registers they take/return), other than attempting to decipher the source code? |
Bill Antonia (2466) 120 posts |
It’s early days. If you look at the supporting C header file “spi” there is a list of SWI names and their numbers. The associated C spiLib contains the code to call the individual SWIs. In all cases if there is a returned value it is in R0 only. Where void is passed the SWI generally requires no parameters, the only exception to this is the function spi_clear_fifo() which is a convenience function to do a specific job but calls PiSPI_WriteControlStatusBits with fixed parameters to do that specific job. There are only six 32 bit registers used in the SPI interface, each function and SWI has the name of the register embedded within its name that it will affect. Generally if one parameter is passed to a C function then one parameter is passed in R0, if two parameters are passed then they are passed in R0 and R1 to the SWI. Functions which end as ‘_bits’ pass a (Edit) bit field offset. Functions which end with ‘_mask’ read the associated register modify only the bits associated in the mask from the passed value then writes back to the register. I do get your point, there is little documentation at present, this module was initially for my own benefit to do some investigations into SPI interfacing and it was only two days ago when Jon posted his query. True I did write the bulk back in August last year but have only looked at it again in the last few days. I think I may have some time tomorrow to begin to fill the meat on the bones of the above. When it is ready, I will attach the documentation to my website. Today I have been looking to add interrupts, buffers and events etc, but will set that aside. |
Bill Antonia (2466) 120 posts |
Have uploaded a text file containing some very basic but usable documentation regarding the modules SWIs to my website where the source can be downloaded (see earlier links in this topic). I will tackle the C library later today, again initially they will be fairly basic. |
Jon Abbott (1421) 2597 posts |
To minimise CPU overhead it might be worth getting DMA working with the SPI driver Unfortunately SPI doesn’t support DMA, p160 of BCM2835 ARM Peripherals.pdf states: SPI controllers do not have DMA connected, hence DMA is not supported. It’s a 1:1 transfer, where you have to write a byte to read one, essentially a high speed serial link so not really suitable for a screen, but should be fine for my needs – namely debugging information. I won’t know if it will be workable as a screen until I test the throughput and performance impact. If you need to software convert 1/2/4/8bpp to true colour then it might be better to compare the new data against the softcopy Good idea, I could screen scrub against a private DA copy of DA2 and only write words that change over SPI. I could also interlace and update every alternate scan line on alternative frames to halve the data throughput. The biggest killer is going to be stuffing the data down SPI, ideally it wants to be in lots of small chunks (aka DMA style) so as to minimise the impact on the system. There’s a couple of options here: 1. Use RTSupport and stuff 1/4 of the data every ms for a refresh over 25fps (may display tearing though) Although HAL_Timers would mean a consistent data throughput at regular intervals, I’m loathed to use it until it’s shareable or can be exclusively locked. I could use it for the debugger but wouldn’t want to make public a GraphicsV driver that relied on it. With support of HOMM2? :) You’re actually on topic, if you take a look at the current JASPP preservation status however, you’ll see HOMM2 is listed as “Missing”, meaning we don’t have it in the archive. If someone would like to kindly donate a copy to the project, I’ll certainly look at getting it running on the Pi. The idea of bolting this screen onto a Pi2 is directly related to your request as: The next release of ADFFS is a big update from a supported game point of view, it now hypervises IRQv/IRQ1v and can fixup reads/writes to page zero in realtime so just about any legacy game should just work – essentially the older the game and the more dodgy things they do at hardware level, the more likely it is to run. The irony being that games that legally do things though RISCOS are more problematic, hence why I’ve yet to implement 26bit Module or WIMP support. Acorn did provide a neat method for fixing Modules as they’re loaded, when they introduced RO3.71, however I can’t use it as it was broken when the 32bit check was added – unfortunately the 32bit check is done before Service_ModulePreInit is issued, so no 26bit Modules can be patched at Pre-Init. The irony is that from the Modules I’ve patched to date manually, most just need the 32bit flag turning on. The general rule of thumb on Modules appears to be that if they were hand written they’re generally 32bit compatible, if they were compiled in C they won’t work – which is irony in itself. HOMM2 is a (relatively) new title so will almost certainly need 26bit Module support and possibly WIMP support, but as I haven’t seen it I’m not 100% certain on that. It’s also possibly RiscPC only and to date I’ve concentrated on legacy Archimedes of which the VMM is complete enough for gaming. Internally, ADFFS actually converts most of IOC/VIDC/MEMC to IOMD equivalents, so I’ve future proofed it to add a RiscPC VMM at some stage. VIDC20 should work as will the IOC registers that overlap IOMD but if a game is using any IOMD specific registers I’ll need to extend it before they’ll run. The biggest problem with IOMD is the lack of any detail, the ARM7500 TRM gives some hints but as for specifics they’re sadly lacking, I’d have to pick apart RPCEmu to see how it works where games fail. Having said that, I suspect that no RiscPC game is going to be going direct to hardware, they should all be going through legal RISCOS methods of which ADFFS already either hypervises or paravirtualizes parts of RISCOS to ensure the game thinks its on 26bit and the OS thinks its seeing 32bit. Going off-topic for a second, I’ve really enjoyed the technical challenges of the next release of ADFFS, the now 700+ hours I’ve put into it have been very rewarding and where the realisation that a full blown hypervisor could be possible with a few core RISCOS additions and as a free side-effect of this, apps could run on multiple cores in their own VMM’s and feed back into the WIMP on the primary core…neatly solving the RISCOS unicore issue and in addition to that, as the WIMP would also have to be paravirtualized to allow multiple cores to feed into it, PMT could also be implemented for existing WIMP apps on the primary core. Essentially the hypervisor would sit between the WIMP and all apps and take over the task switching, breaking out of apps when the machine is in a known state and issuing Wimp_Poll back to the WIMP so it can switch apps as normal. Being a hypervisor, its fully aware of Callbacks Device Vector claims, Vector claims etc so has control of the hardware vectors and VM state. I’ve added the DMB instructions Thanks for the updated version and taking the time to document the SWI’s. |
Andrew Conroy (370) 724 posts |
Thanks Bill. That might allow more people to make good use of your module :-) |
David Feugey (2125) 2687 posts |
Send an email to temp1267@riscos.fr
Perfect for an AMP system :) |
Steve Pampling (1551) 7921 posts |
I’m curious – when you1, in lunatic fashion, hack a 26 bit module to put in the appropriate header elements for 32 bit it loads. What happens if you access any of the 26 bit code in the module is a totally different thing though, but it does load. 1 OK, “when I” is the correct phrase since you and other people have more sense. |
Jeffrey Lee (213) 6046 posts |
To minimise CPU overhead it might be worth getting DMA working with the SPI driver That’s the SPI/BSC slave controller (chapter 11), not the main SPI controller (chapter 10) If anyone’s tempted to give it a go, it’s also worth bearing in mind this document errata The biggest killer is going to be stuffing the data down SPI, ideally it wants to be in lots of small chunks (aka DMA style) so as to minimise the impact on the system. There’s a couple of options here: Can’t you do everything from within an IRQ handler, triggered by the FIFO level triggers? (see 10.6.2 in the datasheet) If you go down the DA softcopy approach, with the bpp conversion handled by TickerV or a callback or something, then the IRQ handler responsible for the SPI transfer will only have to stream data from your softcopy buffer, keeping the interrupt processing very light. |
Rick Murray (539) 13385 posts |
Steve: I think he means there was a point where a compiled C module was built to be 26/32 neutral so it doesn’t fiddle with the PSR (like ORRing into R14 or tbe TEQPs), or try to reload it on exit (LDMFD …^), nor assumes flags will be preserved across calls, and probably has some generic way to set V for reporting something went wrong; so in theory it should work on either system. But… that’s theory. Reality may differ. (^_^) |
Steve Pampling (1551) 7921 posts |
Oh, but I meant taking a module with all those 26 bit things in and seeing what happens. Thinking about it, modules form so many of the 26 bit obstacles to using older programs. If only there was a simple system for updating. 1 making my own explosives when I was in school wasn’t on the headmaster and his chief constable friends list of safe activities either. |