BlocklyProp icon indicating copy to clipboard operation
BlocklyProp copied to clipboard

i2c blocks

Open MatzElectronics opened this issue 7 years ago • 13 comments

These are done, but require testing

MatzElectronics avatar Sep 23 '18 23:09 MatzElectronics

Who is working on the docs for these blocks?

@mrodriguez-parallax - Can you test these blocks and report back?

zfi avatar Nov 28 '18 00:11 zfi

We need docs and testing on this issue please.

zfi avatar Dec 11 '18 22:12 zfi

See unpub node 1673 for draft block ref content

Steph-Parallax avatar Dec 12 '18 00:12 Steph-Parallax

These blocks don't work yet. Here is a list of changes that can be made to the C code the blocks emit to get single byte exchanges to work. I will take a look at multi-byte next (soon I hope).

In the C code the i2c controller receive block emits, remove & from i2cInBuf in i2c_in call.

When an I2C block causes an i2c_init call to be added to the code, it needs to put the SCL value in the first argument and the SDA value in the second.

In the C code the i2c controller send block emits, the i2cInBuf needs to be populated before the call to i2c_out, not after. It would probably be better to name it i2cBuf, or have separate i2cIn/Out buffers.

AndyLindsay avatar Dec 14 '18 23:12 AndyLindsay

@AndyLindsay @zfi here are the changes recommended above: https://github.com/parallaxinc/BlocklyProp-cdn/pull/83

MatzElectronics avatar Dec 18 '18 18:12 MatzElectronics

I retested the MMA7455 accelerator for some basic I2C communication and also did some multi-byte addressing and waiting for busy with the the 24LC512. Both generated working C code.

i2c eeprom 24LC512 string across 128 byte boundary i2c eeprom 24LC512 int i2c MMA7455 z-axis

The only gotcha or surprise so far was that I had to use the "Other" board type to get access to P28 and P29 for the Propeller's EEPROM bus. I'm guessing the rationale was to prevent a user from modifying their own EEPROM program. Since it would take some concerted effort to modify the EEPROM, it's probably safe to allow I2C access to the P28 and P29 lines on the FLiP and Activity Board. The ones to remove would be P26 and P27 on the FLiP and Activity Board since since LED and D/A circuits could interfere. Especially on the Activity Board, P26 and P27 are behind RC filters and output buffers. Unidirectional, so no SDA, and RC + slew won't be good for SCL either.

AndyLindsay avatar Dec 27 '18 02:12 AndyLindsay

Although the result of a store to and retrieve from EEPROM operation comes out right, the order the bytes are transmitted and received in is the reverse of what the block says. The i2c send block transmits bytes LSB first when it is set to MSB first. Likewise, the i2c receive block receives bytes LSB first when it is set to MSB first.

Also, when a send or receive block is set to LSB first, it makes the 4th argument in the i2c_write/read call negative. Instead, it should make the 6th argument negative when it is set to MSB first.

I think this can be resolved in 2 steps:

  • Make the default setting LSB first and make it emit the code that is currently emitted by the MSB first setting.
  • Make the alternate setting MSB first, and cause it to generate code with a negative 6th argument in the i2c_write/read call. All other arguments in that call should be non-negative.

Example: Send with the default LSB first setting

item = [01020304] hexadecimal

i2c controller send [4] bytes of data [item] [LSB first] to register [32768] length [2] bytes at device address [1010000 binary] SDA [29] SCL [28]

// ------ Libraries and Definitions ------
#include "simpletools.h"

// ------ Global Variables and Objects ------
int item;
i2c *i2c29;
unsigned char i2cBuf[4] = {0, 0, 0, 0};

// ------ Main Program ------
int main() {
  i2c29 = i2c_newbus(28, 29, 0);
  item = (0x01020304);
  i2cBuf[3] = (item >> 24) & 255;
  i2cBuf[2] = (item >> 16) & 255;
  i2cBuf[1] = (item >> 8) & 255;
  i2cBuf[0] = (item) & 255;
  i2c_out(i2c29, 0b1010000 & 0x7F, 32768, 2, i2cBuf, 4);
}  

Example: Send with the alternate MSB first setting

item = [01020304] hexadecimal

i2c controller send [4] bytes of data [item] [MSB first] to register [32768] length [2] bytes at device address [1010000 binary] SDA [29] SCL [28]

// ------ Libraries and Definitions ------
#include "simpletools.h"

// ------ Global Variables and Objects ------
int item;
i2c *i2c29;
unsigned char i2cBuf[4] = {0, 0, 0, 0};

// ------ Main Program ------
int main() {
  i2c29 = i2c_newbus(28, 29, 0);
  item = (0x01020304);
  i2cBuf[3] = (item >> 24) & 255;
  i2cBuf[2] = (item >> 16) & 255;
  i2cBuf[1] = (item >> 8) & 255;
  i2cBuf[0] = (item) & 255;
  i2c_out(i2c29, 0b1010000 & 0x7F, 32768, 2, i2cBuf, -4);      // <- Note 4 changed to -4
}

Example: Receive with the default LSB first setting

i2c controller receive [4] bytes [LSB] first from register [32768] length [2] bytes at device address 1010000 binary as [Decimal] store in [item2] SDA [29] SCL [28]

// ------ Libraries and Definitions ------
#include "simpletools.h"

// ------ Global Variables and Objects ------
int item2;
i2c *i2c29;
unsigned char i2cBuf[4] = {0, 0, 0, 0};

// ------ Main Program ------
int main() {
  i2c29 = i2c_newbus(28, 29, 0);
  i2c_in(i2c29, 0b1010000 & 0x7F, 32768, 2, i2cBuf, 4);
  item2 = ((i2cBuf[3] << 24) | (i2cBuf[2] << 16) | (i2cBuf[1] << 8) | i2cBuf[0]);
}

Example: Receive with the alternate MSB first setting

i2c controller receive [4] bytes [MSB] first from register [32768] length [2] bytes at device address 1010000 binary as [Decimal] store in [item2] SDA [29] SCL [28]

// ------ Libraries and Definitions ------
#include "simpletools.h"

// ------ Global Variables and Objects ------
int item2;
i2c *i2c29;
unsigned char i2cBuf[4] = {0, 0, 0, 0};

// ------ Main Program ------
int main() {
  i2c29 = i2c_newbus(28, 29, 0);
  i2c_in(i2c29, 0b1010000 & 0x7F, 32768, 2, i2cBuf, -4);    // <- Note 4 changed to -4
  item2 = ((i2cBuf[3] << 24) | (i2cBuf[2] << 16) | (i2cBuf[1] << 8) | i2cBuf[0]);
}

AndyLindsay avatar Dec 28 '18 22:12 AndyLindsay

If you start with an i2c controller send block that looks like this:

i2c controller send [4] bytes of data [item] [LSB first] to register [32768] length [2] bytes at device address [1010000 binary] SDA [29] SCL [28]

... it kind of looks like the register address will be transmitted LSB first and the device address is 2 bytes long. Here is one way that might bake it clearer:

i2c controller send Data [4 bytes] [LSB] first [item] Register [2 bytes] address 32768 Bus SCL 28 SDA 29 Device address 1010000 binary

Conversely, the i2c receive command to get that data back from an EEPROM is currently

i2c controller receive [4] bytes [LSB] first from register [32768] length [2] bytes at device address 1010000 binary as [Decimal] store in [item2] SDA [29] SCL [28]

It might be more clear as something like:

i2c controller receive Data [4 bytes] [LSB] first [item] Register [2 bytes] address 32768 Bus SCL 28 SDA 29 Device address 1010000 binary

AndyLindsay avatar Dec 28 '18 23:12 AndyLindsay

One final thought for now, it might be better to only have the MSB/LSB option appear when more than one byte of data is sent/received.

AndyLindsay avatar Dec 28 '18 23:12 AndyLindsay

I was able to incorporate nearly all of @AndyLindsay 's suggestions, so these blocks should now be ready for a comprehensive re-test.

MatzElectronics avatar Jun 05 '19 14:06 MatzElectronics

I didn't see any issues in the retest.

AndyLindsay avatar Jul 31 '19 19:07 AndyLindsay

Thanks, @PropGit for pointing out that we no longer have access to P28 and P29. Those should not be off limits.

My tests this morning were no good because I used old blocks that I had saved instead of dragging out new ones. True, the code those blocks generated was correct, but it looks like the blocks have been modified too. It's going to need to be retested.

AndyLindsay avatar Aug 01 '19 02:08 AndyLindsay

@AndyLindsay - Sure!

PropGit avatar Aug 01 '19 13:08 PropGit