-
Notifications
You must be signed in to change notification settings - Fork 30
Fixes #179 - I2C tutorial added #181
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
d601803
df50c18
6b0e741
537b8cc
334c440
0980466
56a8e7a
904d788
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
# I2C | ||
|
||
I2C is a simple-to-use communication protocol which can have more than one master, with the upper bus speed defined, and only two wires with pull-up resistors are needed to connect almost _unlimited_ number of I2C devices. | ||
|
||
Each slave device has a unique address. Transfer from and to master device is serial and it is split into 8-bit packets. All these simple requirements make it very simple to implement I2C interface even with cheap microcontrollers that have no special I2C hardware controller. You only need 2 free I/O pins and few simple I2C routines to send and receive commands. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. "Transfer from and to master device is serial and it is split into.." -> "Information transfer to and from the master device is serial. Data is split into 8-bit packets." There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Second sentence uses "simple" twice but should ideally avoid it. Something more like "An I2C interface can be implemented even with cheap microcontrollers that have no special I2C hardware controller. The protocol only requires two I/O pins..." There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. "...a few simple I2C routines" – what's a more descriptive word than "simple"? Do you mean that they require few lines of code? That the logic is easily parsed? Is the descriptor helpful, or superfluous? |
||
|
||
Let us get the accelerometer values using the I2C protocol. We will be using the [The Tessel Accelerometer](https://www.seeedstudio.com/Tessel-Accelerometer-Module-p-2223.html) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Beginning the phrasing with "In this tutorial..." and a description of the end result of the tutorial might be more clear here |
||
|
||
[Refer to the datasheet for the accelerometer module to follow along](http://www.nxp.com/docs/en/data-sheet/MMA8452Q.pdf) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. A bit more description would be helpful here. "The Tessel Accelerometer Module is based around the MMA84 accelerometer chip from NXP. We use the datasheet to.." |
||
|
||
 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. A little description would be good here too: make it clear that this is the hardware setup a tutorial follower will need to replicate There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. A potentially more useful Fritzing diagram (in addition to this one): since we're just using the I2C pins, what if you draw a fritzing diagram where just the pins you actually need are connected by wires between module and Tessel? And possibly label red/black wires for power vs SCL/SDA in whatever color you make them |
||
|
||
```js | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What is this code going to do? Introduce it! |
||
var tessel = require('tessel'); | ||
|
||
// Connect to device | ||
var port = tessel.port.A; // Use the SCL/SDA pins of Port A | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The comment doesn't seem to match the code. How do we know from the code that we're using the SCL/SDA pins? How would a reader ensure they are using the right pins in their hardware setup? |
||
|
||
// This address of the Slave has been taken from https://github.com/tessel/accel-mma84/blob/master/index.js#L15 | ||
// It can also be found in Table 10 - I2C device address sequence on page number 17 of the datasheet. | ||
var slaveAddress = 0x1D; // Specific to device | ||
|
||
var i2c = new port.I2C(slaveAddress); // Initialize I2C communication | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. May be useful to note that this is a built-in function of a Tessel port, possibly even reference where in the code port.I2C is defined. Up to you, bonus points ;) |
||
|
||
// Details of I2C read and I2C transfer | ||
var numBytesToRead = 1; // Read back this number of bytes | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why are we reading back this number of bytes here? |
||
|
||
// Read data over I2C using i2c.read | ||
i2c.read(numBytesToRead, function (error, dataReceived) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What is it we're reading here? |
||
// Print data received (buffer of hex values) | ||
console.log('Buffer returned by I2C slave device ('+slaveAddress.toString(16)+'):', dataReceived); | ||
|
||
}); | ||
|
||
// Read/Receive data over I2C using i2c.transfer | ||
// 0x0D is the WHO_AM_I Register which sends back an acknowledgement to the master for starting the communication | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would be good to reference a page in the datasheet There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fixed |
||
// Information about 0x0D can also be found in Table 11 - Register address map on page number 19 of the datasheet. | ||
|
||
i2c.transfer(new Buffer([0x0D]), numBytesToRead, function (error, dataReceived) { | ||
// Print data received (buffer of hex values) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is the whitespace correct here? Looks a little too tabbed in |
||
// The returned buffer from the I2C slave device should be [0x2A] as specified in the register address map on page number 19 of the MMA84 datasheet | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think if I were following this tutorial, I'd want to know "why 0x2a? Does it mean anything?" Not sure how to make this clearer |
||
console.log('Buffer returned by I2C slave device ('+slaveAddress.toString(16)+'):', dataReceived); | ||
|
||
}); | ||
|
||
/* | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This feels like it should be a break between code examples. The first one tells you "yes, the accelerometer is connected and we have communication"; the second one gets you the actual values. It would be helpful to see the concepts introduced separately There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. (and possibly also helpful for readers to see that that's how it's usually done– you write the simplest possible code first to establish a correct setup, then later write the code that does what you really need) |
||
|
||
In the i2c.transfer function, the dataReceived consists of all the 6 bytes of data (which is 48 bits of data) : 2 bytes each for the x, y, and z values. | ||
This can be seen on page 20 and 21 of the accelerometer datasheet. | ||
Each of the x, y, and z acceleration values have two registers associated with them for storing the 12 bit long sample. | ||
The first 8 bits are stored in their respective OUT_MSB registers. These are the Most Significant first 8 bits. | ||
The next 4 bits are stored in their respective OUT_LSB registers. The remaining 4 bits are occupied | ||
by 0s. These lower 4 bits (bits 0, 1, 2, and 3 of the OUT_LSB registers) are redundant bits which are not required. The OUT_LSB and OUT_MSB store the 2's complement form of the coordinates. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good! |
||
|
||
The organization of the registers can be seen in the datasheet inside section 6.1 (Data Registers), page number - 21 | ||
The register address for OUT_X_MSB is 0x01. This can be found at Page 19 of https://www.nxp.com/docs/en/data-sheet/MMA8452Q.pdf | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Useful to note that this chip lets you read registers sequentially, so that's why we only need to specify the first address |
||
|
||
*/ | ||
i2c.transfer(new Buffer([0x01]), 6, function (error, dataReceived) { | ||
|
||
// This is an exception. If an error is generated, it will throw the error | ||
if (error) throw error; | ||
|
||
//This array is going to store the final x,y,z values | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Typo: spacing |
||
var out=[]; | ||
|
||
// The for loop is iterated 3 times, in order to extract the x,y, and z acceleration values. | ||
for (var i=0;i<3;i++){ | ||
|
||
/* | ||
|
||
We have 16 bits to put together - the most significant 8 bits and the least significant 8 bits so that we can interpret them as one number. This combined value is placed in gCount variable using the OR operation. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Least significant 4 bits, right? |
||
The gCount variable is a bitwise OR operation between two binary numbers: | ||
1. The 8 bits in OUT_MSB for a given coordinate are shifted left by 8 bits in order to make space for the remaining 8 bits | ||
of the OUT_LSB. | ||
2. The OUT_LSB of the respective coordinate. | ||
|
||
*/ | ||
var gCount=(dataReceived[i*2] << 8) | dataReceived[(i*2)+1]; | ||
|
||
// The gCount number of the respective coordinate is right shifted by 4 to get rid of the unused lower 0 bits which are 4 in number yielding the 12 bits that the datasheet specifies each coordinate has on page number 21. | ||
gCount=gCount >> 4; | ||
|
||
/* | ||
|
||
The x,y, and z accelerometer values are stored in their respective OUT_MSB and OUT_LSB registers as negative values i.e. their 2's complement form. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Odd spacing in this chunk of comments |
||
Therefore in order to obtain the correct values, check whether the most significant bit of the OUT_MSB is 1 or 0 i.e whether the coordinate value is negative or positive. | ||
If it is negative (checked using 0x7F, which is the maximum possible number that can be made from 7 bits), the if condition changes it to a 2's complement form, thus making it positive and adding a "-" sign in front of it. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would it be clearer to use > 0b01111111 ? |
||
127 is checking whether we have a 0 or a 1 at the first position - basically its sign. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Redundant with the previous line (now that you're using hex)? |
||
|
||
*/ | ||
if (dataReceived[i*2] > 0x7F) { | ||
gCount = -(1 + 0xFFF - gCount); // Transform into negative 2's complement | ||
} | ||
|
||
// Lastly, normalize the coordinate to get a value between 0 and 1, dividing gCount by 2^10. | ||
out[i] = gCount / ((1<<12)/(2*2)); | ||
} | ||
console.log('The x, y, z values are :',out); | ||
|
||
}); | ||
``` | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Does your code actually work & respond appropriately when run? I think you're missing a crucial step– look up SYSMOD in the datasheet |
||
|
||
### Sample Ouput | ||
|
||
 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is your Fritzing diagram, not output |
||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Great! Can you think of a bonus question to ask? |
||
[Datasheet for accelerometer module](http://www.nxp.com/docs/en/data-sheet/MMA8452Q.pdf) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These seem like a separate section, not part of Sample Output |
||
|
||
[More Informatiom on I2C Communication](https://learn.sparkfun.com/tutorials/i2c) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
strike "simple-to-use"– that's a value judgment and might make some readers think along the lines of "well, I couldn't figure it out..". You can say it's "designed to be simple" if you want, but I think the rest of your description (two wires, unlimited devices) is more helpful