Obsolete IIC calls in the RPi build?
Chris Evans (457) 1614 posts |
Do we know why the RPi IIC bus would appear to be attempting to communicate with a generic EEPROM 24AA01/24LC010x type device at various times? To be more specific, it tries talking to an IIC device on address A0 right after power-up, before any sign of booting on the monitor, then again just as the RISC OS desktop appears. After this it seems to talk now and then all the while RISC OS is running, and then predictably at shutdown. |
Theo Markettos (89) 919 posts |
&A0 is the address of the PCF8583 RTC/CMOS RAM chip on Acorn-class machines, isn’t it? Is it probing for one of those? Not sure what the CMOS widgets use for their EEPROM. |
Sprow (202) 1158 posts |
Most generic EEPROM is at &A0 too. |
Chris Evans (457) 1614 posts |
I’m not sure how things work. But I would have thought that the Pi build should not have included code that tries accessing non Pi hardware! Am I wrong? |
Sprow (202) 1158 posts |
Um, yes and no. The ‘CMOS widget’ is accessed via I2C but as this isn’t a real bus it’s not exposed via the IIC_Op calls, it’s mapped via the HAL NVMemory API. There are a multitude of ways of getting at I2C memory, there’s OS_Byte, OS_NVRAM, OS_IICOp, IIC_Op (avoid!), and OS_Hardware. That list is also in rough level of increasing complexity and decreasing abstraction – but each has its pros and cons. The kernel will try to find EEPROM and RTC on start up, and can optionally fall back to the HAL or can use only the HAL. It’s not incorrect that a RPi kernel tries probing the IIC on start up, if nothing is found, nothing happens. What’s the actual question here? Why do you perceive it to be a bug? What problem are you trying to solve? |
Chris Evans (457) 1614 posts |
I thought maybe it had been left in inadvertently and wondered if it might cause unforeseen problems in the future! |
Chris Evans (457) 1614 posts |
Upon reflection I can see it makes perfect sense to test for an EEPROM and use it if found. I can’t though think of any reason why once its failed to find an EEPROM during booting it attempts to occasionally access one and again at shutdown! |
Mike Cook (1781) 3 posts |
I have been trying to use SYS “IIC_Control” on the RPi and I find it unstable. I can greatly improve things if I add a 10mS delay after each call to it and drop the processor speed to 700MHz. However it still crashes after about 10 minuets.Even using “XIIC_Control” crashes. For example reading a PCF8591 analogue input register crashes with an abort on data transfer after:- |
Robin Hounsome (1539) 25 posts |
bq I have been trying to use SYS “IIC_Control” on the RPi and I find it unstable Can confirm that, using an ADS7828 12bit 8 channel AtoD on a issue 1 board with no overclocking. As Mike says adding a delay does appear to make it a bit more stable but just delays the onset of the error. For me the ‘abort on data transfer at &FC0105D0’ is consistent *where reports address is not in any module |
Martin Bazley (331) 379 posts |
I think you’re supposed to be using OS_IICOp, with IIC_Control officially deprecated. |
Rick Murray (539) 13840 posts |
Given that IIC_Control appears to call OS_IICOp (if I read the sources correctly), it does rather beg the question of what’s going wrong? Is it a problem specifically with the IIC_Control SWI, with the IIC subsystem, or some other sort of interaction? Mike, Robin – the obvious question is “does this happen if you use OS_IICOp?”. |
Robin Hounsome (1539) 25 posts |
Thanks for the pointer Martin and to answer Ricks question, yes, using OS_IICOp I was able to take out the delays and the code ran in a continuous loop for approx 40 minutes. Which is some 15 times longer than using IIC_Control without the delay. I’ll leave it running over-night and see what happens |
Nathanael Smith (1763) 17 posts |
Sorry to interupt – after trying the patience of people on the R-Pi forum (http://www.raspberrypi.org/phpBB3/viewtopic.php?f=55&t=13218&p=222719#p222719) I finally got IIC_Control working in BASIC from my Pi. I would now like to use this SWI from C as I know it works, but because the SWI is depreciated I cannot find its number to call it using swix(). I would be grateful if someone could provide me with that call number? My personal view is that some consideration should be given to developing a unique SWI for the R-Pi that corresponds more closely with the Broadcom Serial Controller as the controller is an absurdly easy to use piece of hardware that automatically perfoms alot of the donkey work usually done in software. I don’t know about other RISC machines but I’m guessing they might not have anything quite like it. I question the need for anything other than a very minimal wrapper for this controller and wonder whether the current SWIs exploit it fully. I have had previous success completing I2C transactions under Linux by just accessing the BSC registers directly. I would prefer to do this under RISC OS instead of using a SWI, but do not understand how to expose the BSC registers to RISC OS’ memory management system. Any advice on that or examples of calling IIC_Control / OS_IICOp from either C or BASIC would be appreciated. |
Jeffrey Lee (213) 6048 posts |
The wiki has information about OS_IICOp, but nothing about IIC_Control yet. However I can tell you that IIC_Control’s SWI number is 0×240. I was about to say that I couldn’t think of a reason why OS_IICOp should be more stable than IIC_Control, but after checking the IIC_Control sources I’ve just spotted a critical bug in the 32bit conversion, so the SWI is using the exit procedure for a 26bit processor mode instead of for a 32bit processor mode! I’ll submit a fix, it should show up in tomorrow’s development ROMs. |
Rick Murray (539) 13840 posts |
Just to clarify – when you say “Serial Controller”, you are talking about IIC, yes? Not the UARTs? My personal view… is that either IIC_Control (deprecated or otherwise) and OS_IICOp should be the points of entry to the IIC system. If the hardware is that easy to use, then it’s not going to be difficult to wrap accesses to it in some code that will hang from the official IIC routines. In this way, your software will remain compatible with other boards that offer IIC because you will be using generic OS access points rather than system-specific stuff, plus – I might add – not inventing a different method of doing exactly the same thing as should already be provided by the OS.
Can’t speak for the Beagle, but on original generation Archimedes (and IIRC, the RiscPC), the IIC interface was bit-bashed on two I/O pins of the IOC/IOMD.
I don’t think (but might be wrong about OS_IICOp, the wiki needs some examples or something) that the chained-transaction method is supported. That’s the one that goes like: [start][devid/write][data][data][data][start][devid/read][nnnnn][stop] (in other words, a start without a stop to change from write to read without an entirely new IIC operation) But – note well – it appears that the Pi’s IIC hardware cannot handle clock stretching unless said stretching happens during the ACK (hardware bug?). Furthermore, there is a timeout mechanism of up to ‘x’ clk ticks. On a slow bus (100kHz), this will give you up to, IIRC, 2.5mS. If your microcontroller takes longer than 2.5mS to get stuff done (this is not uncommon if transferring data to EEPROM etc), the clock stretching will fail with a timeout. As for the start-without-stop, some (most) devices support this, some don’t. Murphy’s Law says the one that doesn’t will be the one you wanted to use. I am lead to understand that some microcontroller IIC library code is shonky and you might be better off writing your own code to handle the IIC directly (ie interrupts and bit-banging).
Directly accessing hardware is usually frowned upon. As soon as you bypass the OS’s code, you tie your program down to that particular board. Are you aware that there are multiple IIC buses in the Pi and that somewhere along the way (rev. 2 board?) they were swapped over? The OS is aware. If you bypass the OS, you will need to be aware too [plus be willing to revise/update your software for any other changes/quirks].
I use IIC_Control, never sat down to work out the syntax of OS_IICOp. Yeah, I’m lazy… but more than that, IIC_Control is dead simple. I don’t need to remember or look up flags, pointers, which-word-is-which, etc. In BASIC:
And, off the top of my head, in C it might look like:
And, for good measure, my preferred method, ‘cos I’m like this…
The bit with taking R1 from R12 with adding IIC_WORKSPACE is because R12 points to an array structure with some workspace at the end. The rest ought to be clear now, if you can read assembler, that is. (^_^) For what it is worth, I would not use |
Nathanael Smith (1763) 17 posts |
Thanks for the quick responses Jeffrey Lee – its great to see that there are eagle-eyed people doimg a thorough job! Rik Murray – many thanks – plenty to think about – should keep me quiet for a bit! you stated: “My personal view… is that either IIC_Control (deprecated or otherwise) and OS_IICOp should be the points of entry to the IIC system. If the hardware is that easy to use, then it’s not going to be difficult to wrap accesses to it in some code that will hang from the official IIC routines. In this way, your software will remain compatible with other boards that offer IIC because you will be using generic OS access points rather than system-specific stuff, plus – I might add – not inventing a different method of doing exactly the same thing as should already be provided by the OS.” I accept that that is generally true for most people in most situations. You go on to state that: “Directly accessing hardware is usually frowned upon. As soon as you bypass the OS’s code, you tie your program down to that particular board. Are you aware that there are multiple IIC buses in the Pi and that somewhere along the way (rev. 2 board?) they were swapped over? The OS is aware. If you bypass the OS, you will need to be aware too [plus be willing to revise/update your software for any other changes/quirks].” Again, generally true, but not for me. Like many Pi users I am an ametuer hacker/hobbyist and my code is specifically for a specific board dedicated to a single project for my own private purposes, so compatability is not an issue. I don’t think I’m unique there and I believe that people such as myself should not be discouraged from considering direct BSC register access as an option for I2C control. Having initially learned how to do I2C transfers this way, I can’t help being amused/frustrated by other labour saving methods that are infact more complicated. For this reason direct access is still my preference and I will continue to look for a way to acheive this under RISC OS as it is my favourite Pi OS. RISC OS is my favourite as it is user friendly and efficient as it is designed for the processor runs on. In adition RISC OS and Linux variants there are now also ports of ChibiOS and FreeRTOS available for the Pi. I have flirted with these but they seem unfriendly and unfamiliar and would require me to learn new programming techniques and how to set up cross-compiling tool chains on additional machines, which seems a bit extreme. I suspect that RISC OS on the Pi could satisfy a niche for being a cuddly (quasi) RTOS in the hacker/hobbyist community if given the right support. You have already mentioned unnecessary overheads when using parts of RISC OS which is something best avoided in time-critical applications such as a control system for a quad-copter or self-balancing robot. To my mind that is another argument for direct register access. If anyone could point me in the right direction about this I would be grateful. I am already grateful for the examples above which I shall experiment with and adapt. Many thanks again and keep up the good work! |
Robin Hounsome (1539) 25 posts |
I left a single tasking BASIC loop running for approx. 17 hours. It completed approx. 25.5 million calls to OS_ICCOp without error. Downloaded the 2012-11-28 05:34:39 ROM and re-ran a similar BASIC program but this time calling IIC_Control. After approx 52 minutes I stopped it with 320,000 calls to IIC_Control completed without error. That is far, far longer than I could get with the RC6 version of the ROM So it looks like Jeffrey’s fix of last night has worked, thanks for that. I’m sure OS_IICOp has got advantages, but I’m with Rick, IIC_Control is easier to use, certainly for the simpler IIC tasks. Edit: The above figures would suggest the IIC_Control is much slower than OS_IICOp. Not so, I’d left a delay loop in the IIC_Control version of the program |
Rick Murray (539) 13840 posts |
(^_^) I’m the one with the ‘c’.
Brilliant – hack away!
Well… um… <hesitant> yes and no maybe. I can tell you how to map in stuff, it’s not hard. But, like, have you considered what might happen if the IIC hardware generates interrupts or events that the operating system responds to? I guess this is why it used to be good that all the IIC stuff was a separate module – if you needed to hijack the thing, you could replace it with a dummy module and the OS would then be out of the loop.
<giggle> You mean like a car is more complicated than walking? I suspect what you perceive as being complicated is because you are used to a way that suits how you think.
Then with a smile I will suggest OS_Memory.
Which in BASIC ought to be something like:
What is happening is you are telling the OS to map in 256 bytes from the specified physical address. It will return with a logical address that you should use, which will be mapped to the physical address requested. Details at: https://www.riscosopen.org/wiki/documentation/show/OS_Memory%2013 Note that this is a permanent mapping. There doesn’t seem to be a “done with this, thanks” call. I would hope RISC OS is smart enough that if you ran this 100 times, you’d get one mapping and 100 pointers to it, not 100 mappings. ;-)
Chibi!? Is it small and cute? http://en.wikipedia.org/wiki/Chibi_%28term%29
Not unusual. I have an SD Card for my eeePC which contains a version of PortableUbuntu which is able to run the Neuros development environment to allow me to compile code for my PVR.
Already posted that idea. Just… don’t have the quad-copter. ;-) [probably just as well – I’d spend forever playing with it, get fired from my job for not turning up, my cat would be repossessed, internet would be disconnected, and I’d wind up desolate and destitute without even a place to plug in my charger… <violins, etc>]
Ooooh, now what sort of robot are we talking? It has taken a ridiculous amount of research and work to get Asimo to where it is now [ http://en.wikipedia.org/wiki/Asimo ]; and I should say the wiki page describes the processor as… “ASIMO has a three-dimensional computer processor that was created by Honda and consists of a three stacked die, a processor, a signal converter and memory.”.
And RISC OS can help you poke stuff directly. [oo-err!] Good luck! |
Theo Markettos (89) 919 posts |
You can get full memory access, you just need to be in Supervisor mode. To do that:
You can achieve supervisor mode by calling SWI OS_EnterOS. If you are always in control (ie you have no callbacks, interrupt handlers, etc) you can do this in an assembler fragment in a BASIC or other program (EnterOS, set registers, LeaveOS). For setting registers from the command line, look at *Memory (read) and *MemoryA (write), notably with the ‘P’ flag to indicate physical memory addresses. There’s one caveat that *MemoryA will read the register before it writes it – I think there’s a flag to disable that. *MemoryI is also useful as a disassembler. Rick’s call to OS_Memory is interesting – despite what the comment says, the flags he’s supplied asks for the memory to be read/write in unprivileged modes. So if that works you can then just poke those addresses. |
Rick Murray (539) 13840 posts |
The comment is correct – I’m saying I want read/write privilege (as in, the ability to peek’n’poke that bit of memory), not “read/write in a privileged mode” which is…usually the default, isn’t it? |
Nathanael Smith (1763) 17 posts |
Thanks again – I’m going to try this approach: #define PORTBASE 0×40000000 // example address unsigned int volatile * const port = (unsigned int *) PORTBASE; The variable port is a constant pointer to a volatile unsigned integer, so we can access the memory-mapped register using: *port = value; // write to port as described here: http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.faqs/ka3750.html(struggling with textile – cut and paste to address bar – don’t click) In specific relation to the Pi it should look something like: #define IOBASE 0×20000000 #define BSC0_BASE (IOBASE + 0×205000) unsigned int volatile * const BSC0_C=(unsigned int *) (BSC0_BASE+0x0); //——————— Function to write one byte to I2C bus void LDByteWriteI2C(unsigned short int device_addr, unsigned short int the_register, unsigned char the_data_byte) I am struggling with the SWI OS_EnterOS to get supervisor access - _kernel_swi(0×16); gives me : error: expected declaration specifiers or ‘…’ before numeric constant everything else compiles ok Any help in calling SWI OS_EnterOS and SWI OS_LeaveOS from C very much appreciated…. |
Rick Murray (539) 13840 posts |
Of course, assuming you have defined: It doesn’t matter if it takes/returns no registers, you still have to provide them or else the compiler will sulk, and as you might have noticed, the error messages are written in nerdish. |
Nathanael Smith (1763) 17 posts |
Thanks again Rick – its still sulking :¬< Should I #include anything like “kernel.h” or “swis.h” first ? thanks in advance for your patience |
Jeffrey Lee (213) 6048 posts |
Including both kernel.h and swis.h is generally a good start if you want to call SWIs. swis.h mainly contains definitions for all the SWI numbers (well, most of them), while kernel.h has things like _kernel_swi_regs, _kernel_os_error, etc. Also, I’ll tell you now that calling OS_EnterOS straight from C (or from BASIC) will fail badly – hence Theo’s suggestion to use an assembler fragment. OS_EnterOS and OS_LeaveOS both cause the OS to switch you to a different CPU mode; OS_EnterOS switches to supervisor mode (SVC), while OS_LeaveOS switches to user mode (USR). Apart from granting you different memory access permissions, each CPU mode also has its own link register, and perhaps more importantly, its own stack pointer, pointing to a completely different stack. So if you called OS_EnterOS from C, the code would completely lose track of where it’s meant to be returning to and die horribly (not to mention some of the other registers like the stack limit not being valid anymore). You’ve basically got three solutions to the problem:
|
Jeffrey Lee (213) 6048 posts |
…but having said that, the OS_Memory 13 example that Rick gives should result in the memory being mapped in with full read/write privileges for user mode. I say “should” because I’m not sure offhand if OS_Memory 13 is smart enough to modify the access rights of the existing mapping (that was created by the HAL IIC driver). I think it will allow the access to be changed (or at least return a second mapping which has the access you want), but I’m not sure.
Yes, OS_Memory 13 will detect attempts to map in the same address multiple times and return just the one mapping. And there’s no “done with this, thanks” call because OS_Memory 13 is the “map in IO permanent” call. If you want a temporary mapping then there’s OS_Memory 14 and OS_Memory 15 – but those (a) aren’t suitable if you need multiple areas mapped in at once (there’s just a single 1MB window which the most recently requested address gets mapped in to), and (b) you can’t specify the access flags so the memory will be available in privileged modes only. |