parallaxinc / BlocklyProp

Blockly based visual programming editor for Propeller C
MIT License
44 stars 25 forks source link

i2c blocks #1553

Open MatzElectronics opened 6 years ago

MatzElectronics commented 6 years ago

These are done, but require testing

zfi commented 5 years ago

Who is working on the docs for these blocks?

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

zfi commented 5 years ago

We need docs and testing on this issue please.

Steph-Parallax commented 5 years ago

See unpub node 1673 for draft block ref content

AndyLindsay commented 5 years ago

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.

MatzElectronics commented 5 years ago

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

AndyLindsay commented 5 years ago

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 commented 5 years ago

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:

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 commented 5 years ago

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 commented 5 years ago

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.

MatzElectronics commented 5 years ago

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

AndyLindsay commented 5 years ago

I didn't see any issues in the retest.

AndyLindsay commented 5 years ago

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.

PropGit commented 5 years ago

@AndyLindsay - Sure!