Reading MOSI data from Bosch ASIC

Hi there,

EDIT - please see latest posts. EDIT.

I'm using a Bosch ASIC in a project I'm toying with, and am trying to communicate with the chip over SPI, essential to its use. However, the Bosch datasheet is incredibly thin on SPI information. Here's all the SPI information on the chip.

I'm struggling with how to write code to interface with this chip, in my SPI setup I've got the following, to correspond with the MSB first requirements, and the clock frequency set as the chip is max 2MBaud.

SPI.begin();
SPI.setBitOrder(MSBFIRST); // sets SPI data transfer to MSB first
SPI.setDataMode(SPI_MODE0); // sets SPI mode to MODE0
SPI.setClockDivider(SPI_CLOCK_DIV8); // sets shared clock rate to 16Mhz / 8 = 2Mhz

...and to actually read from a register, RD: 78H, I've got the following...

// select chip
digitalWrite(chip_select, LOW);

// send generic 01 address prefix

// send 78H hexadecimal address
SPI.transfer(0x78H);

// send parity?
SPI.transfer();

// send don't care, if needed?

// send 8 dummy bits of data

Any advice would be greatly appreciated;

1) The generic 01 pre address, I'm not sure how to send this? What to type 2) I'm not sure what parity is? 3) Don't care, I guess I need to send a bit, 1 or 0? 4) How would I go about sending those 8 dummy bits? 5) That leads me into a whole other ball park, how do I go about reading/saving the bits sent back?

Many thanks in advance.

Where is the link to the datasheet?

MarkT: Where is the link to the datasheet?

My bad...

http://www.bosch-semiconductors.de/media/pdf_1/einzeldownloads/engine_management/CJ125_Product_Info.pdf

EDIT - As you may have guessed, this is my first venture in to SPI. The hex values I've used in the above code, I've realised don't make sense to me as hex is A through F.... and I've got an H, so I've gone over to binary.

So if I want to transmit a 16bit dataframe, for example, to read the diagnoses register 78h, or decimal 120 - this is what I'm stuck with, where I put this address etc.

78H means 78 hex. It’s sometimes written as 78H.

In C we write it as 0x78, not 78H (and definitely not 0x78H).

Did 0x78H actually get past the compiler? It shouldn’t My gcc (solaris and linux) dies with “error: invalid suffix “H” on integer constant” when I tried 0x78H.

-j

Did 0x78H actually get past the compiler? It shouldn't My gcc (solaris and linux) dies with "error: invalid suffix "H" on integer constant" when I tried 0x78H.

Ha, no don't worry - it did not. I hadn't yet attempted to compile as I knew the code was far from complete, just earlier on I did have a check and no, it threw it out with the same error as you stated. The problem is, looking at the sequence - I need to enter 0, 1, address bit 1, address bit 2, address bit 3, address bit 4, parity bit (not sure what this is), then any bit as it's don't care, followed by 8 random bits. Found some more info here. http://www.breitband-lambda.de/pages/lambda---english/controlling-the-cj125.php?lang=EN However, I'm not sure how to enter those 4 address bits, as I know I've now got 0x78, but have no idea how to enter this as four bits? I'm thinking perhaps, send a 0, send a 1, send a four bit byte that corresponds to 0x78 (is there such thing as a four bit byte?, then send the parity bit, then either a 1 or 0.

EDIT - You know when you try and work something out all day, then for some reason it clicks. Well, it's clicked.

The address MUST be of the format 01xxxxx-, where x is 0 or 1, and - is don't care.

So, converting ALL the possible hex addresses to 8 bit binary, they all start 01, so for example - the diag register of 0x78 is 01111000, so to read from that one simply transmits 01111000, followed by any other 8 bits.

However, how do I go about capturing the data bits that come back in response?

SPI.transfer returns a byte result, capture those...

MarkT:
SPI.transfer returns a byte result, capture those…

That’s exactly what I’m trying to achieve - I just don’t know the syntax or whatnot to achieve this, the SPI library page in the playground has no mention either…

http://gammon.com.au/spi

Lots of datasheets have a description of the SPI protocol. It doesn't mean you have to implement it.

If the device works according to the SPI standards, then the SPI implementation on the Arduino should be able to talk to it.

If it doesn't, give up. I think it is beyond the capability of most people to identify the problem, and how would you correct it, even if you could diagnose it ?

What this means, is that you have to have the wiring correct. And you have to be making the correct calls from your arduino sketch to the functions of the SPI interface library.

http://gammon.com.au/spi

Brilliant, cheers. So, reading the text under heading "sending & receiving data", because the appropriate data is sent back is sent back at the same time as the data going out, let's check I understand this right.

SPI.transfer (4) would send the value of 4, of course - and writing an a = SPI.transfer(4) would capture the data returned as a result of sending a value of 4 out over SPI?

a = SPI.transfer (4);
// a is now 1

b = SPI.transfer (3);
// b is now 2

If I send my data as two binary bytes, as below for example, the data I then capture back using the above method, does that come back and save as a binary byte? I've added two entries in to my code to declare bytes to save the contents of the registers.

byte ident_reg_contents = B00000000;
byte diag_reg_contents = B00000000;

SPI.transfer(B01111000);
diag_reg_contents = SPI.transfer(B00000000);

If it doesn't, give up

That somewhat defeats the point of learning to interface with the SPI bus....

jtw11: SPI.transfer (4) would send the value of 4, of course - and writing an a = SPI.transfer(4) would capture the data returned as a result of sending a value of 4 out over SPI?

No, as my page tries to explain.

As each bit is sent and received simultaneously it isn't possible for a single transfer to send data and receive a response (to that same data).

... because the appropriate data is sent back is sent back at the same time as the data going out, let's check I understand this right.

It is possible to receive valid data as you send stuff, but it won't be in direct response to the byte being sent.

As each bit is sent and received simultaneously it isn't possible for a single transfer to send data and receive a response (to that same data).

Ah, okay. Maybe i've misunderstood the following from your web page, perhaps you could steer me on the correct track?

Basically, while the master hardware is clocking out bits on the MOSI line (master out, slave in) it is also clocking in bits on the MISO (master in, slave out). Effectively, during one character time, it both sends and receives one byte. Hence the name of the function SPI.transfer.

char a, b;

a = SPI.transfer (4);

// a is now 1

b = SPI.transfer (3);

// b is now 2

...as I have replicated this in my code, for example - to read the contents of the identification register, IDENT_REG, at address B01001000 - I have done as you have, declared storage for the received data, I have then sent out the address B01001000, then sent a second transfer B00000000. The second transfer being the dummy bits required to retrieve the contents of the register.

byte ident_reg_contents = B00000000;

SPI.transfer(B01001000);
ident_reg_contents = SPI.transfer(B00000000);

Certainly that's how this page is implying to do so - http://www.breitband-lambda.de/pages/lambda---english/controlling-the-cj125.php?lang=EN

The 'Read Access' bit of the datasheet shows that too, send the address - then send 8 dummy bits, and the return of each dummy bit is the corresponding register entry, MSB first.

Perhaps i'm missing something fundamental? Do you mean my methodology is wrong, or my syntax to save the returned data is wrong? If it's of any help, I have no compiler errors at all.

Many thanks so far!

SPI.transfer(B01001000);

How about:

SPI.transfer(0x48);

That's easier to read, and matches the spec.

Their page seems to suggest the data is in 16-bit lots:

So without the device to hand it is hard to be sure. You could try the 16-bit approach:

SPI.transfer(0);  // MS byte
SPI.transfer(0x48);  // LS byte

byte result1 = SPI.transfer(0);
byte result2 = SPI.transfer(0);

And then try printing those.

I went over to binary to make dealing with setting individual bits on or off, as I can simply line them up with their graphical display in the datasheet. On that note, may one mix hex & binary in the same code?

Their page seems to suggest the data is in 16-bit lots

Yes, page 5 specifies a 16-bit data frame.

However, sorry - I'm not with you on your 16 bit approach example?

Each transfer sends 8 bits, so 2 x transfer does 16 bits.

[quote author=Nick Gammon link=topic=144703.msg1089071#msg1089071 date=1359160367] Each transfer sends 8 bits, so 2 x transfer does 16 bits. [/quote]

I see - but your example sends a 0 byte, then the address byte, should that not occur in the opposite order?

Then, it's followed by another two 0 bytes?

It agrees with the diagram on the previous page. Take a look at the SI (bottom left) part. There are 4 x 8-bit bytes there, with the MSB first (most significant). So sending a zero first fills up the most significant bits with zero, followed by the register address. Then we fire off two more zeroes which do the transfer which lets the device reply.

There are four bytes? I’ve read the diagram as two bytes, due to the presence of the bit 14 and bit 13 labels on the same diagram?

However, I don’t see what ADR0 & ADR1 refer to?

Does a 16 bit data frame not include the address? Does the fact that reading and writing from/to the same register uses a different address play a part here?

I’ve got a BASIC code that interfaces with this chip, however the notes are a rough German to English translation, and I know nothing yet of BASIC. I’ll post it up in the morning, it’s late this side of the planet :slight_smile:

OK, I misread that bit.

Still that clearly shows you send a byte and get one back afterwards.

So:

SPI.transfer(0x48);  // command
byte result = SPI.transfer(0);

If there's any more confusion, post all your code, not just a couple of lines. You need to set SS low before those two transfers.