User avatar
Grumpy Mike
Posts: 931
Joined: Sat Sep 10, 2011 7:49 pm
Location: Manchester (England England)
Contact: Website

Re: I2C Access

Mon Nov 26, 2012 11:43 pm

Tank has recommended I use OS_IICOp in another post and states he has never attempted to use IIC_Control, as it is 'less current'.
That is odd because as I understand it OS_IICOp is a super set of IIC_Control. I am using XSWI to access it. That means if there is an error then tell me about it instead of crashing. That is why it should not crash. If IIC_Control is not stable then neither is anything else that calls it.
Not convinced that SWI's are necessary.
No RISC OS always needs SWI's to access part of the operating system.

pygmy_giant
Posts: 1562
Joined: Sun Mar 04, 2012 12:49 am

Re: I2C Access

Tue Nov 27, 2012 12:01 am

I understand that - what I meant was that perhaps we can just access the BSC registers instead.

Thanks for posting the results of your tests.

User avatar
Grumpy Mike
Posts: 931
Joined: Sat Sep 10, 2011 7:49 pm
Location: Manchester (England England)
Contact: Website

Re: I2C Access

Tue Nov 27, 2012 10:17 am

pygmy_giant wrote:what I meant was that perhaps we can just access the BSC registers instead.
Accessing the chip's registers is only one step needed to make an I2C driver. Yes you can access this from BASIC in exactly the same way you can do in C. Look at Tank's GPIO code for this but it is not going to produce a sudden cure.

Latest tests dropping the processor clock down to 700MHz seems to improve matters but it is still quite random. I found the listing 4, with a delay and a print out of how many times the PCF8591 was accessed showed it crashed after 21560, or 14922 or 48272 times.
This shows that the basic system call is functioning and it is the right way to access it. If there were something fundamentally wrong with the software on the users side it would crash immediately. What is broken is the I2C drivers.

Looking at your posts you also seem to be getting errors other than the abort on data transfer. These are to do with other things wrong in your code or hardware. Can you cay what hardware you are using, how you have wired up the address lines and post what code you have. Then at least you could get it going for a few minuets.

pygmy_giant
Posts: 1562
Joined: Sun Mar 04, 2012 12:49 am

Re: I2C Access

Tue Nov 27, 2012 1:45 pm

Thanks

Code: Select all

REM set bus address to that of 'Flexel I2C Data Aquisition Module'
Address% = &48

REM add write bit to bus address
To_Pass% = (Address% << 1) + %1

REM Create pointer to 4 byte data block and load first 3 blocks with data to set LCD screen backlight brightness to 0 as a test
DIM Data% 3
Data%?0 = &FE
Data%?1 = &03
Data%?2 = &00

REM Initiate transfer
SYS "IIC_Control",To_Pass%,Data%,3
Gives me 'IIC error'

Is there a way to get more verbose error messages?

Are ther any obvious errors or should I re-check my wirining (this wiring was previously working under linux)

User avatar
Grumpy Mike
Posts: 931
Joined: Sat Sep 10, 2011 7:49 pm
Location: Manchester (England England)
Contact: Website

Re: I2C Access

Tue Nov 27, 2012 2:27 pm

Can you post a link to the device you are using.
This line is wrong

Code: Select all

To_Pass% = (Address% << 1) + %1
try

Code: Select all

To_Pass% = (Address% << 1) + 1
But what is the real address of the I2C device in your interface and how have you wired up the external address lines ( if any ). The read address always has a 1 in the least significant bit and the write address a 0.

Generally you are best defining your read and write address:-

Code: Select all

readAddress% =  &49
writeAddress% = &48

or if you have the address wrong in that above

Code: Select all

readAddress% =  &91
writeAddress% = &90
Also this bit is wrong:-
REM Create pointer to 4 byte data block
To do that you have to dimension the data as 4 not 3.

pygmy_giant
Posts: 1562
Joined: Sun Mar 04, 2012 12:49 am

Re: I2C Access

Tue Nov 27, 2012 2:56 pm

Thanks

After having made the ammendments you suggested, I still get 'IIC_error' but now I also get the multi-chromatic screen of death on re-boot so perhaps that's progress.

The device I'm using is this one:

http://www.njbsmith.net/miscellaneous/I2C_FLEXEL.pdf

I will re-check my wiring but last time I looked it was working correctly (under Linux/C) - there could be a loose connection I suppose.

Edit: If I include a random print statement in the code I get more verbose error messages. Changing the address to a non existent one gives me 'No acknowledge from IIC device' while changing it back gives me 'IIC error'. This seems to indicate that my wiring is correct as the device is atleast being acknowledged.

I'm still confused about the read/write bit - I think my code should read '+0' as I am writing in this example. My device has only one address (but many internal sub-registers). My understanding of the hardware is that returned information is placed on the BSC FIFO, so how does that translate here? How could I access it? Would it be in the data block (Data%)?

User avatar
Grumpy Mike
Posts: 931
Joined: Sat Sep 10, 2011 7:49 pm
Location: Manchester (England England)
Contact: Website

Re: I2C Access

Tue Nov 27, 2012 3:13 pm

I notice that this is a 5V device with pull up resistors on board. You need to remove those pull up resistors or go through a bi-directional level translator before you can use this safely with the Pi.
Sadly it is a poor sort of data sheet and doesn't mention what sort of address it gives.

The LCD back light needs a resistor in it. Have you wired one in. It sounds like you haven't and indeed the back light is turning on and putting too much load on the 5V and so resting the Pi. If you haven't got a resistor of the right size then just disconnect it and see if the code still resets your Pi.

User avatar
Grumpy Mike
Posts: 931
Joined: Sat Sep 10, 2011 7:49 pm
Location: Manchester (England England)
Contact: Website

Re: I2C Access

Tue Nov 27, 2012 3:15 pm

My understanding of the hardware is that returned information is placed on the BSC FIFO,
No that is not right. You have to specifically ask for data. The way you describe is how the SPI works not I2C.

pygmy_giant
Posts: 1562
Joined: Sun Mar 04, 2012 12:49 am

Re: I2C Access

Tue Nov 27, 2012 3:24 pm

Thanks.

I am using a bi-directional level shifter. I had this set-up working perfectly under Linux/C so I know it is not an external hardware issue.

The addresses I use in my example are on pages 9 and 16.

When I retrieved data using C under Linux with this set up, I just kept pulling it off the BSC FIFO like pulling white rabbits out of a magician's hat. I did of course first send the device an I2C command to request that it sends the data to the BSC. My understanding is that the BSC does alot of the donkey work that is often otherwise done by sowtware, hence the magicians hat fifo register. This is also my experience (using C under Linux).

User avatar
Grumpy Mike
Posts: 931
Joined: Sat Sep 10, 2011 7:49 pm
Location: Manchester (England England)
Contact: Website

Re: I2C Access

Tue Nov 27, 2012 3:40 pm

Code: Select all

The addresses I use in my example are on pages 9 and 16.
Yes but it is ambiguous it doesn't say what sort of address it is, that is if it is an 8 bit address that includes the read / write bit or a 7 it address that does not.
When I retrieved data using C under Linux with this set up, I just kept pulling it off the BSC FIFO like pulling white rabbits out of a magician's hat. I did of course first send the device an I2C command to request that it sends the data to the BSC.
The "setup" normally specifies how many bytes you are going to read from it.

Did you try disconnecting the back light?

pygmy_giant
Posts: 1562
Joined: Sun Mar 04, 2012 12:49 am

Re: I2C Access

Tue Nov 27, 2012 6:47 pm

Thanks.

I believe it uses an 8 bit address system - the read/writeyness is implicit in the command sent.

I am just checking how I did this before...

I have not disconnected the LCD backlight as it is neither possible nor necessary. I have had exactly this hardware set-up working under Linux. It is not a hardware issue, It is a software issue.

Thanks.

pygmy_giant
Posts: 1562
Joined: Sun Mar 04, 2012 12:49 am

Re: I2C Access

Tue Nov 27, 2012 7:23 pm

Before I just placed the correct values in the correct BSC registers or in the FIFO as outlined on page 28 of the Broadcom Data Sheet and then initiated the transfer via the Control register by telling it whether I wanted to read or write.

If it was a write command this external device obeyed my command, if it was a read command it dutifully sent the data to the BSC where it stayed in the FIFO for me to retrieve at my leisure.

To be honest, because the Broadcom Serial Controller on the Pi is so well thought out and so easy to use, I don't understand how these SWI's actually do any useful work on this machine other than perpetuate a legacy.

At the risk of sounding ungreatful, I don't really want RISCOS to do anything for me re: I2C except get ot of the way. Under Linux I had to acheive this by exposing the BSC registers to the virtual memory system using the Linux /dev/mem streams. Not sure of the equivelant method in RISCOS.

Any pointers in this respect would be appreciated.

Hope I have not offended anyone - thanks for your patience.

Steve Drain
Posts: 105
Joined: Tue Oct 30, 2012 2:08 pm
Location: Exeter UK

Re: I2C Access

Tue Nov 27, 2012 8:07 pm

Sorry to poke my nose in, but I would not like inaccurate information about BASIC to go into the record.

pygmy_giant is correct: %1 (binary) is identical to 1 and DIM Data% 3 reserves 4 bytes.

I think Grump Mike has spotted one reason there might be a problem in that you are using a R/W bit of 1 in a write instruction and I, too, think it ought to be 0.

In general, I think it would be advisable to use SWI "OS_IICOp" rather than "IIC_Control" on the basis that it is more likely to be up-to-date.

Purely speculatively, and a bit of a stab in the dark, based on what I have done with another IIC device, you could try this:

Code: Select all

 DIM send% 23, data% 15
 REM write transfer block
 send%!00=90 :REM write address
 send%!04=data%
 send%!08=3  :REM write 3 bytes
 REM read transfer block
 send%!12=91 :REM read address
 send%!16=data%
 send%!20=0  :REM no write bytes
 REM data block
 data%?0=&FE :REM command byte
 data%?1=&03 :REM set lcd brightness
 data%?2=&00 :REM off
 SYS"OS_IICOp",send%,1 :REM send 1 transfer block to write only
If the command is to read data then send both, 2, transfer blocks. Good luck. :)

pygmy_giant
Posts: 1562
Joined: Sun Mar 04, 2012 12:49 am

Re: I2C Access

Tue Nov 27, 2012 8:41 pm

Thanks Steve - your code did not work - but after running it my original IIC_control code that Mike helped me to debug started spontaneously working for no discernable reason (loose connection?!)

Working code:

Code: Select all

PRINT "Working IIC_Control code"

REM set bus address to that of 'Flexel I2C Data Aquisition Module'
Address% = &48

REM add write bit to bus address
To_Pass% = (Address% << 1) + 0

REM create pointer to 4 byte data block and load first 3 blocks with data
DIM Data% 4
Data%?0 = &FE
Data%?1 = &03
Data%?2 = 0     :REM value in range 0 - 250 to set LCD backlight brightness

REM initiate transfer
SYS "IIC_Control",To_Pass%,Data%,3
so thankyou both for your time and patience I hope someone else finds this useful :D :D :D

Next step - see if I can impliment this SWI in C...

pygmy_giant
Posts: 1562
Joined: Sun Mar 04, 2012 12:49 am

Re: I2C Access

Tue Nov 27, 2012 10:36 pm

Well, I went to the ROOL website to lookup the SWI number for IIC_Control and it was not there because it is old and officialy depreciated.

I was asked instead to log-in, after which I was asked to write a manual entry for this SWI :?

I might try to get Steve's code working afterall before translating it to C.

theom
Posts: 73
Joined: Wed Jun 13, 2012 2:53 pm

Re: I2C Access

Wed Nov 28, 2012 9:19 pm

It's not there because nobody has written a wiki page for it yet... and you get the usual wiki response if you try and view that noexistent page :-| I don't think there's been any decision on whether it's been deprecated.

According to a recent post on the ROOL forum, there was a bug in IIC_Control which means it wasn't returning correctly. This should be fixed in tonight's development. ROM autobuild (download it from the ROOL website).

User avatar
Grumpy Mike
Posts: 931
Joined: Sat Sep 10, 2011 7:49 pm
Location: Manchester (England England)
Contact: Website

Re: I2C Access

Sun Dec 02, 2012 10:45 pm

bug in IIC_Control which means it wasn' ... correctly
Have you a link for that post, I haven't managed to chase it down.


pygmy_giant
Posts: 1562
Joined: Sun Mar 04, 2012 12:49 am

Re: I2C Access

Wed Dec 05, 2012 9:35 pm

Code: Select all

// Demo code to access Flexel Data Aquisition Module
// from Raspberry Pi (first Revision) running RISC OS via BSC registers



//------------- Header files

#include <stdio.h>
#include <stdlib.h>
#include "kernel.h"
#include "swis.h"



//------------- Define start of BSC register addresses

#define BSC_physical 0x20205000



//------------- Define read, write, cleansing and status values

#define BSC_C_I2CEN (1 << 15)
#define BSC_C_INTR (1 << 10)
#define BSC_C_INTT (1 << 9)
#define BSC_C_INTD (1 << 8)
#define BSC_C_ST (1 << 7)
#define BSC_C_CLEAR (1 << 4)
#define BSC_C_CLEAR_II (1 << 5)
#define BSC_C_READ 1

#define CLEAR_FIFO  BSC_C_CLEAR|BSC_C_CLEAR_II
#define START_READ  BSC_C_I2CEN|BSC_C_ST|BSC_C_CLEAR|BSC_C_READ
#define START_WRITE BSC_C_I2CEN|BSC_C_ST

#define BSC_S_CLKT (1 << 9)
#define BSC_S_ERR (1 << 8)
#define BSC_S_RXF (1 << 7)
#define BSC_S_TXE (1 << 6)
#define BSC_S_RXD (1 << 5)
#define BSC_S_TXD (1 << 4)
#define BSC_S_RXR (1 << 3)
#define BSC_S_TXW (1 << 2)
#define BSC_S_DONE (1 << 1)
#define BSC_S_TA 1

#define CLEAR_STATUS BSC_S_CLKT|BSC_S_ERR|BSC_S_DONE



//------------- Function declarations

unsigned int Memory_Map(unsigned int base);
void ByteWriteI2C(unsigned short int device_addr, unsigned char data_byte);
unsigned short int ByteReadI2C(unsigned short int device_addr);
void wait_i2c_done();
void init();
void EmptyFIFO();
void MultiByteWriteI2C(unsigned short int device_addr, unsigned short int length);
void MultiByteReadI2C(unsigned short int device_addr, unsigned short int length);


//------------- Set up pointers to mapped logical address

unsigned char FIFO_access[16]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
unsigned int BSC_logical;
unsigned int volatile * BSC_C;
unsigned int volatile * BSC_S;
unsigned int volatile * BSC_DLEN;
unsigned int volatile * BSC_A;
unsigned int volatile * BSC_FIFO;



void init()
{
printf("\ninitialising...\n");
BSC_logical = Memory_Map(BSC_physical);
BSC_C = (unsigned int *) (BSC_logical+0x0);
BSC_S = (unsigned int *) (BSC_logical+0x04);
BSC_DLEN = (unsigned int *) (BSC_logical+0x08);
BSC_A = (unsigned int *) (BSC_logical+0x0C);
BSC_FIFO = (unsigned int *) (BSC_logical+0x10);
*BSC_C=CLEAR_FIFO;
}



//------------- Map physical addresses to logical addresses

unsigned int Memory_Map(unsigned int base)
{
printf("mapping...");
_kernel_swi_regs r;
r.r[0] = (1 << 17) + 13;
r.r[1] = base;
r.r[2] = 1024;
_kernel_swi(OS_Memory, &r, &r);
return r.r[3];
}



//——————— Function to empty FIFO

void EmptyFIFO()
{
*BSC_C=CLEAR_FIFO;
}



//——————— Function to write one byte to I2C bus

void ByteWriteI2C(unsigned short int device_addr, unsigned char data_byte)
{
printf("\nchanging BSC register values...\n");
*BSC_C=CLEAR_FIFO;
*BSC_S = CLEAR_STATUS;
*BSC_A = device_addr;
*BSC_DLEN = 1;
*BSC_FIFO = data_byte;
printf("starting to write transaction...\n");
*BSC_C = START_WRITE;
wait_i2c_done();
}



//——————— Function to read one byte from I2C bus

unsigned short int ByteReadI2C(unsigned short int device_addr)
{
printf("\nchanging BSC register values to send bus address only...\n");
*BSC_C=CLEAR_FIFO;
*BSC_S = CLEAR_STATUS;
*BSC_A = device_addr;
*BSC_DLEN = 1;
printf("starting to write transaction...\n");
*BSC_C = START_WRITE;
wait_i2c_done();
printf("changing BSC register values to read...\n");
*BSC_S = CLEAR_STATUS;
*BSC_A = device_addr;
*BSC_DLEN = 1;
printf("starting to send transaction...\n");
*BSC_C = START_READ;
wait_i2c_done();
printf("reading one byte from FIFO...\n");
return *BSC_FIFO;
}



//——————— Function to write multiple bytes to I2C bus

void MultiByteWriteI2C(unsigned short int device_addr, unsigned short int length)
{
unsigned short int i=0;
printf("\nchanging BSC register values...\n");
*BSC_C=CLEAR_FIFO;
*BSC_S = CLEAR_STATUS;
*BSC_A = device_addr;
*BSC_DLEN = length;
while(i<length)
{
*BSC_FIFO=FIFO_access[i];
FIFO_access[i]=0;
i++;
}
printf("starting to write transaction...\n");
*BSC_C = START_WRITE;
wait_i2c_done();
}



//——————— Function to read Multiple bytes from I2C bus

void MultiByteReadI2C(unsigned short int device_addr, unsigned short int length)
{
unsigned short int i=0;
printf("\nchanging BSC register values to send bus address only...\n");
*BSC_C = CLEAR_FIFO;
*BSC_S = CLEAR_STATUS;
*BSC_A = device_addr;
*BSC_DLEN = 0;
printf("starting to write transaction...\n");
*BSC_C = START_WRITE;
wait_i2c_done();
printf("changing BSC register values to read...\n");
*BSC_S = CLEAR_STATUS;
*BSC_A = device_addr;
*BSC_DLEN = length;
printf("starting to send transaction...\n");
*BSC_C = START_READ;
wait_i2c_done();
printf("reading multiple bytes from FIFO...\n");
while(i<length)
{
FIFO_access[i]=*BSC_FIFO;
i++;
}
}



//------------- display I2C transaction status

void dump_bsc_status()
{
unsigned int s = *BSC_S;
printf("BSC0_S: ERR=%d  RXF=%d  TXE=%d  RXD=%d  TXD=%d  RXR=%d  TXW=%d  DONE=%d  TA=%d\n",
(s & BSC_S_ERR) != 0,
(s & BSC_S_RXF) != 0,
(s & BSC_S_TXE) != 0,
(s & BSC_S_RXD) != 0,
(s & BSC_S_TXD) != 0,
(s & BSC_S_RXR) != 0,
(s & BSC_S_TXW) != 0,
(s & BSC_S_DONE) != 0,
(s & BSC_S_TA) != 0 );
}



//------------- Function to wait for the I2C transaction to complete

void wait_i2c_done()
{
printf("status before completion - ");
dump_bsc_status();
printf("waiting for transaction to complete...\n");
unsigned short int timeout = 50;
unsigned short int i;
while((!((*BSC_S) & BSC_S_DONE)) && --timeout)
{
i=0;
while(i<5000)
{
i++;
}
}
if(timeout == 0)
printf("wait_i2c_done() timeout. Something went wrong.\n");
printf("status after completion - ");
dump_bsc_status();
}



//------------- Here we go...!

int main(int argc, char **argv)
{
// initialise
init();

// send characters to screen
ByteWriteI2C(0x48,48); //send '0' to lcd
ByteWriteI2C(0x48,49); //send '1' to lcd
ByteWriteI2C(0x48,50); //send '2' to lcd
ByteWriteI2C(0x48,51); //send '3' to lcd
ByteWriteI2C(0x48,52); //send '4' to lcd
ByteWriteI2C(0x48,53); //send '5' to lcd
ByteWriteI2C(0x48,54); //send '6' to lcd
ByteWriteI2C(0x48,55); //send '7' to lcd
ByteWriteI2C(0x48,56); //send '8' to lcd
ByteWriteI2C(0x48,57); //send '9' to lcd

// turn down LCD backlight
FIFO_access[0]=0xFE;
FIFO_access[1]=0x03;
FIFO_access[2]=0x10;
MultiByteWriteI2C(0x48,3);

//read and display time from Real Time Clock
FIFO_access[0]=0xFE;
FIFO_access[1]=0x2A;
MultiByteWriteI2C(0x48,2);
MultiByteReadI2C(0x48,3);
printf("\nTime: %d hours %d minutes %d seconds\n",FIFO_access[2],FIFO_access[1],FIFO_access[0]);
return 0;
}

pygmy_giant
Posts: 1562
Joined: Sun Mar 04, 2012 12:49 am

Re: I2C Access

Fri Dec 07, 2012 7:08 pm

For a second revision board 0x20205000 should be swapped for 0x20804000.

Thanks again to those on the RISC OS Open forum who helped me develop this code and also those on this forum from whom I got the idea.

heuristicjohn
Posts: 39
Joined: Thu Jan 31, 2013 11:55 pm

Re: I2C Access

Thu Mar 07, 2013 3:17 pm

I would much appreciate advice on the following : I am attempting to write data to an EEPROM on the I2C bus (under RISCOS). The device is at address &50, and in the example I write &56 to internal memory location &1234. I then set the memory pointer using a write without data, and then read back the data. My problem is that each of these commands works on its own, but when I execute them in sequence I get the error message "no acknowledge".

Code: Select all

address% =&50
WWrite%= (address%<<1)+0
RRead% = (address%<<1)+1
DIM data% 4
data%?0=&12
data%?1=&34
data%?2 =&56
DIM rdata% 4
rdata%?1=&0
SYS "IIC_Control",WWrite%,data%,3

SYS "IIC_Control",WWrite%,data%,2

SYS "IIC_Control",RRead%,rdata%,1

 PRINT ~rdata%?0

User avatar
Grumpy Mike
Posts: 931
Joined: Sat Sep 10, 2011 7:49 pm
Location: Manchester (England England)
Contact: Website

Re: I2C Access

Thu Mar 07, 2013 3:47 pm

Are you using the development build? I don't think the fix has made it into the normal distribution yet as I don't think there has been a release since this bug was spotted.

heuristicjohn
Posts: 39
Joined: Thu Jan 31, 2013 11:55 pm

Re: I2C Access

Thu Mar 07, 2013 4:01 pm

Are you using the development build? I don't think the fix has made it into the normal distribution yet as I don't think there has been a release since this bug was spotted.
I downloaded RISCOS on February 5th, so it's fairly recent - regret to say I can't quote the version number, as I don't know where to find it.

User avatar
Grumpy Mike
Posts: 931
Joined: Sat Sep 10, 2011 7:49 pm
Location: Manchester (England England)
Contact: Website

Re: I2C Access

Thu Mar 07, 2013 4:24 pm

I downloaded RISCOS on February 5th, so it's fairly recent -
I just checked the one on the download link on this site is from 01/11/2012 version RC6 so it looks like there has not been a release since this was spotted. Is that were you got it from?
Therefore that is your problem. It explains why one use of the code works but not subsequent ones.

heuristicjohn
Posts: 39
Joined: Thu Jan 31, 2013 11:55 pm

Re: I2C Access

Thu Mar 07, 2013 5:24 pm

I just checked the one on the download link on this site is from 01/11/2012 version RC6
Sorry - yes, that is the exact version number. Shall have to keep a beady eye open for the next release. Thanks for your help !

Return to “RISCOS”