Initial Release
This commit is contained in:
5
i2c/CMakeLists.txt
Normal file
5
i2c/CMakeLists.txt
Normal file
@@ -0,0 +1,5 @@
|
||||
if (NOT PICO_NO_HARDWARE)
|
||||
add_subdirectory(bus_scan)
|
||||
add_subdirectory(lcd_1602_i2c)
|
||||
add_subdirectory(mpu6050_i2c)
|
||||
endif ()
|
||||
12
i2c/bus_scan/CMakeLists.txt
Normal file
12
i2c/bus_scan/CMakeLists.txt
Normal file
@@ -0,0 +1,12 @@
|
||||
add_executable(i2c_bus_scan
|
||||
bus_scan.c
|
||||
)
|
||||
|
||||
# Pull in our (to be renamed) simple get you started dependencies
|
||||
target_link_libraries(i2c_bus_scan pico_stdlib hardware_i2c)
|
||||
|
||||
# create map/bin/hex file etc.
|
||||
pico_add_extra_outputs(i2c_bus_scan)
|
||||
|
||||
# add url via pico_set_program_url
|
||||
example_auto_set_url(i2c_bus_scan)
|
||||
70
i2c/bus_scan/bus_scan.c
Normal file
70
i2c/bus_scan/bus_scan.c
Normal file
@@ -0,0 +1,70 @@
|
||||
/**
|
||||
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
// Sweep through all 7-bit I2C addresses, to see if any slaves are present on
|
||||
// the I2C bus. Print out a table that looks like this:
|
||||
//
|
||||
// I2C Bus Scan
|
||||
// 0 1 2 3 4 5 6 7 8 9 A B C D E F
|
||||
// 0
|
||||
// 1 @
|
||||
// 2
|
||||
// 3 @
|
||||
// 4
|
||||
// 5
|
||||
// 6
|
||||
// 7
|
||||
//
|
||||
// E.g. if slave addresses 0x12 and 0x34 were acknowledged.
|
||||
|
||||
#include <stdio.h>
|
||||
#include "pico/stdlib.h"
|
||||
#include "hardware/i2c.h"
|
||||
|
||||
// I2C reserves some addresses for special purposes. We exclude these from the scan.
|
||||
// These are any addresses of the form 000 0xxx or 111 1xxx
|
||||
bool reserved_addr(uint8_t addr) {
|
||||
return (addr & 0x78) == 0 || (addr & 0x78) == 0x78;
|
||||
}
|
||||
|
||||
int main() {
|
||||
// Enable UART so we can print status output
|
||||
stdio_init_all();
|
||||
|
||||
// This example will use I2C0 on GPIO4 (SDA) and GPIO5 (SCL)
|
||||
i2c_init(i2c0, 100 * 1000);
|
||||
gpio_set_function(4, GPIO_FUNC_I2C);
|
||||
gpio_set_function(5, GPIO_FUNC_I2C);
|
||||
gpio_pull_up(4);
|
||||
gpio_pull_up(5);
|
||||
|
||||
printf("\nI2C Bus Scan\n");
|
||||
printf(" 0 1 2 3 4 5 6 7 8 9 A B C D E F\n");
|
||||
|
||||
for (int addr = 0; addr < (1 << 7); ++addr) {
|
||||
if (addr % 16 == 0) {
|
||||
printf("%02x ", addr);
|
||||
}
|
||||
|
||||
// Perform a 1-byte dummy read from the probe address. If a slave
|
||||
// acknowledges this address, the function returns the number of bytes
|
||||
// transferred. If the address byte is ignored, the function returns
|
||||
// -1.
|
||||
|
||||
// Skip over any reserved addresses.
|
||||
int ret;
|
||||
uint8_t rxdata;
|
||||
if (reserved_addr(addr))
|
||||
ret = PICO_ERROR_GENERIC;
|
||||
else
|
||||
ret = i2c_read_blocking(i2c0, addr, &rxdata, 1, false);
|
||||
|
||||
printf(ret < 0 ? "." : "@");
|
||||
printf(addr % 16 == 15 ? "\n" : " ");
|
||||
}
|
||||
printf("Done.\n");
|
||||
return 0;
|
||||
}
|
||||
12
i2c/lcd_1602_i2c/CMakeLists.txt
Normal file
12
i2c/lcd_1602_i2c/CMakeLists.txt
Normal file
@@ -0,0 +1,12 @@
|
||||
add_executable(lcd_1602_i2c
|
||||
lcd_1602_i2c.c
|
||||
)
|
||||
|
||||
# Pull in our (to be renamed) simple get you started dependencies
|
||||
target_link_libraries(lcd_1602_i2c pico_stdlib hardware_i2c)
|
||||
|
||||
# create map/bin/hex file etc.
|
||||
pico_add_extra_outputs(lcd_1602_i2c)
|
||||
|
||||
# add url via pico_set_program_url
|
||||
example_auto_set_url(lcd_1602_i2c)
|
||||
41
i2c/lcd_1602_i2c/README.adoc
Normal file
41
i2c/lcd_1602_i2c/README.adoc
Normal file
@@ -0,0 +1,41 @@
|
||||
= Attaching a 16x2 LCD via I2C
|
||||
|
||||
This example code shows how to interface the Raspberry Pi Pico to one of the very common 16x2 LCD character displays. The display will need a 3.3V I2C adapter board as this example uses I2C for communications.
|
||||
|
||||
[NOTE]
|
||||
======
|
||||
These LCD displays can also be driven directly using GPIO without the use of an adapter board. That is beyond the scope of this example.
|
||||
======
|
||||
|
||||
== Wiring information
|
||||
|
||||
Wiring up the device requires 4 jumpers, to connect VCC (3.3v), GND, SDA and SCL. The example here uses I2C port 0, which is assigned to GPIO 4 (SDA) and 5 (SCL) in software. Power is supplied from the 3.3V pin.
|
||||
|
||||
WARNING: Many displays of this type are 5v. If you wish to use a 5v display you will need to use level shifters on the SDA and SCL lines to convert from the 3.3V used by the RP2040. Whilst a 5v display will just about work at 3.3v, the display will be dim.
|
||||
|
||||
|
||||
[[lcd_1602_i2c_wiring]]
|
||||
[pdfwidth=75%]
|
||||
.Wiring Diagram for LCD1602A LCD with I2C bridge.
|
||||
image::lcd_1602_i2c_bb.png[]
|
||||
|
||||
== List of Files
|
||||
|
||||
CMakeLists.txt:: CMake file to incorporate the example in to the examples build tree.
|
||||
lcd_1602_i2c.c:: The example code.
|
||||
|
||||
== Bill of Materials
|
||||
|
||||
.A list of materials required for the example
|
||||
[[lcd_1602_i2c-bom-table]]
|
||||
[cols=3]
|
||||
|===
|
||||
| *Item* | *Quantity* | Details
|
||||
| Breadboard | 1 | generic part
|
||||
| Raspberry Pi Pico | 1 | http://raspberrypi.org/
|
||||
| 1602A based LCD panel 3.3v | 1 | generic part
|
||||
| 1602A to I2C bridge device 3.3v | 1 | generic part
|
||||
| M/M Jumper wires | 4 | generic part
|
||||
|===
|
||||
|
||||
|
||||
164
i2c/lcd_1602_i2c/lcd_1602_i2c.c
Normal file
164
i2c/lcd_1602_i2c/lcd_1602_i2c.c
Normal file
@@ -0,0 +1,164 @@
|
||||
/**
|
||||
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "pico/stdlib.h"
|
||||
#include "hardware/i2c.h"
|
||||
#include "pico/binary_info.h"
|
||||
|
||||
/* Example code to drive a 16x2 LCD panel via a I2C bridge chip (e.g. PCF8574)
|
||||
|
||||
NOTE: The panel must be capable of being driven at 3.3v NOT 5v. The Pico
|
||||
GPIO (and therefor I2C) cannot be used at 5v.
|
||||
|
||||
You will need to use a level shifter on the I2C lines if you want to run the
|
||||
board at 5v.
|
||||
|
||||
Connections on Raspberry Pi Pico board, other boards may vary.
|
||||
|
||||
GPIO 4 (pin 6)-> SDA on LCD bridge board
|
||||
GPIO 5 (pin 7)-> SCL on LCD bridge board
|
||||
3.3v (pin 36) -> VCC on LCD bridge board
|
||||
GND (pin 38) -> GND on LCD bridge board
|
||||
*/
|
||||
// commands
|
||||
const int LCD_CLEARDISPLAY = 0x01;
|
||||
const int LCD_RETURNHOME = 0x02;
|
||||
const int LCD_ENTRYMODESET = 0x04;
|
||||
const int LCD_DISPLAYCONTROL = 0x08;
|
||||
const int LCD_CURSORSHIFT = 0x10;
|
||||
const int LCD_FUNCTIONSET = 0x20;
|
||||
const int LCD_SETCGRAMADDR = 0x40;
|
||||
const int LCD_SETDDRAMADDR = 0x80;
|
||||
|
||||
// flags for display entry mode
|
||||
const int LCD_ENTRYSHIFTINCREMENT = 0x01;
|
||||
const int LCD_ENTRYLEFT = 0x02;
|
||||
|
||||
// flags for display and cursor control
|
||||
const int LCD_BLINKON = 0x01;
|
||||
const int LCD_CURSORON = 0x02;
|
||||
const int LCD_DISPLAYON = 0x04;
|
||||
|
||||
// flags for display and cursor shift
|
||||
const int LCD_MOVERIGHT = 0x04;
|
||||
const int LCD_DISPLAYMOVE = 0x08;
|
||||
|
||||
// flags for function set
|
||||
const int LCD_5x10DOTS = 0x04;
|
||||
const int LCD_2LINE = 0x08;
|
||||
const int LCD_8BITMODE = 0x10;
|
||||
|
||||
// flag for backlight control
|
||||
const int LCD_BACKLIGHT = 0x08;
|
||||
|
||||
const int LCD_ENABLE_BIT = 0x04;
|
||||
|
||||
#define I2C_PORT i2c0
|
||||
// By default these LCD display drivers are on bus address 0x27
|
||||
static int addr = 0x27;
|
||||
|
||||
// Modes for lcd_send_byte
|
||||
#define LCD_CHARACTER 1
|
||||
#define LCD_COMMAND 0
|
||||
|
||||
#define MAX_LINES 2
|
||||
#define MAX_CHARS 16
|
||||
|
||||
/* Quick helper function for single byte transfers */
|
||||
void i2c_write_byte(uint8_t val) {
|
||||
i2c_write_blocking(I2C_PORT, addr, &val, 1, false);
|
||||
}
|
||||
|
||||
void lcd_toggle_enable(uint8_t val) {
|
||||
// Toggle enable pin on LCD display
|
||||
// We cannot do this too quickly or things don't work
|
||||
#define DELAY_US 600
|
||||
sleep_us(DELAY_US);
|
||||
i2c_write_byte(val | LCD_ENABLE_BIT);
|
||||
sleep_us(DELAY_US);
|
||||
i2c_write_byte(val & ~LCD_ENABLE_BIT);
|
||||
sleep_us(DELAY_US);
|
||||
}
|
||||
|
||||
// The display is sent a byte as two separate nibble transfers
|
||||
void lcd_send_byte(uint8_t val, int mode) {
|
||||
uint8_t high = mode | (val & 0xF0) | LCD_BACKLIGHT;
|
||||
uint8_t low = mode | ((val << 4) & 0xF0) | LCD_BACKLIGHT;
|
||||
|
||||
i2c_write_byte(high);
|
||||
lcd_toggle_enable(high);
|
||||
i2c_write_byte(low);
|
||||
lcd_toggle_enable(low);
|
||||
}
|
||||
|
||||
void lcd_clear(void) {
|
||||
lcd_send_byte(LCD_CLEARDISPLAY, LCD_COMMAND);
|
||||
}
|
||||
|
||||
// go to location on LCD
|
||||
void lcd_set_cursor(int line, int position) {
|
||||
int val = (line == 0) ? 0x80 + position : 0xC0 + position;
|
||||
lcd_send_byte(val, LCD_COMMAND);
|
||||
}
|
||||
|
||||
static void inline lcd_char(char val) {
|
||||
lcd_send_byte(val, LCD_CHARACTER);
|
||||
}
|
||||
|
||||
void lcd_string(const char *s) {
|
||||
while (*s) {
|
||||
lcd_char(*s++);
|
||||
}
|
||||
}
|
||||
|
||||
void lcd_init() {
|
||||
lcd_send_byte(0x03, LCD_COMMAND);
|
||||
lcd_send_byte(0x03, LCD_COMMAND);
|
||||
lcd_send_byte(0x03, LCD_COMMAND);
|
||||
lcd_send_byte(0x02, LCD_COMMAND);
|
||||
|
||||
lcd_send_byte(LCD_ENTRYMODESET | LCD_ENTRYLEFT, LCD_COMMAND);
|
||||
lcd_send_byte(LCD_FUNCTIONSET | LCD_2LINE, LCD_COMMAND);
|
||||
lcd_send_byte(LCD_DISPLAYCONTROL | LCD_DISPLAYON, LCD_COMMAND);
|
||||
lcd_clear();
|
||||
}
|
||||
|
||||
int main() {
|
||||
// This example will use I2C0 on GPIO4 (SDA) and GPIO5 (SCL)
|
||||
i2c_init(I2C_PORT, 100 * 1000);
|
||||
gpio_set_function(4, GPIO_FUNC_I2C);
|
||||
gpio_set_function(5, GPIO_FUNC_I2C);
|
||||
gpio_pull_up(4);
|
||||
gpio_pull_up(5);
|
||||
// Make the I2C pins available to picotool
|
||||
bi_decl( bi_2pins_with_func(4, 5, GPIO_FUNC_I2C));
|
||||
|
||||
lcd_init();
|
||||
|
||||
static uint8_t *message[] =
|
||||
{
|
||||
"RP2040 by", "Raspberry Pi",
|
||||
"A brand new", "microcontroller",
|
||||
"Twin core M0", "Full C SDK",
|
||||
"More power in", "your product",
|
||||
"More beans", "than Heinz!"
|
||||
};
|
||||
|
||||
while (1) {
|
||||
for (int m = 0; m < sizeof(message) / sizeof(message[0]); m += MAX_LINES) {
|
||||
for (int line = 0; line < MAX_LINES; line++) {
|
||||
lcd_set_cursor(line, (MAX_CHARS / 2) - strlen(message[m + line]) / 2);
|
||||
lcd_string(message[m + line]);
|
||||
}
|
||||
sleep_ms(2000);
|
||||
lcd_clear();
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
BIN
i2c/lcd_1602_i2c/lcd_1602_i2c.fzz
Normal file
BIN
i2c/lcd_1602_i2c/lcd_1602_i2c.fzz
Normal file
Binary file not shown.
BIN
i2c/lcd_1602_i2c/lcd_1602_i2c_bb.png
Normal file
BIN
i2c/lcd_1602_i2c/lcd_1602_i2c_bb.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 261 KiB |
12
i2c/mpu6050_i2c/CMakeLists.txt
Normal file
12
i2c/mpu6050_i2c/CMakeLists.txt
Normal file
@@ -0,0 +1,12 @@
|
||||
add_executable(mpu6050_i2c
|
||||
mpu6050_i2c.c
|
||||
)
|
||||
|
||||
# Pull in our (to be renamed) simple get you started dependencies
|
||||
target_link_libraries(mpu6050_i2c pico_stdlib hardware_i2c)
|
||||
|
||||
# create map/bin/hex file etc.
|
||||
pico_add_extra_outputs(mpu6050_i2c)
|
||||
|
||||
# add url via pico_set_program_url
|
||||
example_auto_set_url(mpu6050_i2c)
|
||||
43
i2c/mpu6050_i2c/README.adoc
Normal file
43
i2c/mpu6050_i2c/README.adoc
Normal file
@@ -0,0 +1,43 @@
|
||||
= Attaching a MPU6050 accelerometer/gyroscope via I2C
|
||||
|
||||
This example code shows how to interface the Raspberry Pi Pico to the MPU6050 accelerometer/gyroscope board. This device uses I2C for communications, and most MPU6050 parts are happy running at either 3.3 or 5v. The Raspberry Pi RP2040 GPIO's work at 3.3v so that is what the example uses.
|
||||
|
||||
[NOTE]
|
||||
======
|
||||
This is a very basic example, and only recovers raw data from the sensor. There are various calibration options available that should be used to ensure that the final results are accurate. It is also possible to wire up the interrupt pin to a GPIO and read data only when it is ready, rather than using the polling approach in the example.
|
||||
======
|
||||
|
||||
== Wiring information
|
||||
|
||||
Wiring up the device requires 4 jumpers, to connect VCC (3.3v), GND, SDA and SCL. The example here uses I2C port 0, which is assigned to GPIO 4 (SDA) and 5 (SCL) in software. Power is supplied from the 3.3V pin.
|
||||
|
||||
[NOTE]
|
||||
======
|
||||
There are many different manufacturers who sell boards with the MPU6050. Whilst they all appear slightly different, they all have, at least, the same 4 pins required to power and communicate. When wiring up a board that is different to the one in the diagram, ensure you connect up as described in the previous paragraph.
|
||||
======
|
||||
|
||||
|
||||
[[mpu6050_i2c_wiring]]
|
||||
[pdfwidth=75%]
|
||||
.Wiring Diagram for MPU6050.
|
||||
image::mpu6050_i2c_bb.png[]
|
||||
|
||||
== List of Files
|
||||
|
||||
CMakeLists.txt:: CMake file to incorporate the example in to the examples build tree.
|
||||
mpu6050_i2c.c:: The example code.
|
||||
|
||||
== Bill of Materials
|
||||
|
||||
.A list of materials required for the example
|
||||
[[mpu6050-bom-table]]
|
||||
[cols=3]
|
||||
|===
|
||||
| *Item* | *Quantity* | Details
|
||||
| Breadboard | 1 | generic part
|
||||
| Raspberry Pi Pico | 1 | http://raspberrypi.org/
|
||||
| MPU6050 board| 1 | generic part
|
||||
| M/M Jumper wires | 4 | generic part
|
||||
|===
|
||||
|
||||
|
||||
110
i2c/mpu6050_i2c/mpu6050_i2c.c
Normal file
110
i2c/mpu6050_i2c/mpu6050_i2c.c
Normal file
@@ -0,0 +1,110 @@
|
||||
/**
|
||||
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "pico/stdlib.h"
|
||||
#include "hardware/i2c.h"
|
||||
|
||||
/* Example code to talk to a MPU6050 MEMS accelerometer and gyroscope
|
||||
|
||||
This is taking to simple approach of simply reading registers. It's perfectly
|
||||
possible to link up an interrupt line and set things up to read from the
|
||||
inbuilt FIFO to make it more useful.
|
||||
|
||||
NOTE: Ensure the device is capable of being driven at 3.3v NOT 5v. The Pico
|
||||
GPIO (and therefor I2C) cannot be used at 5v.
|
||||
|
||||
You will need to use a level shifter on the I2C lines if you want to run the
|
||||
board at 5v.
|
||||
|
||||
Connections on Raspberry Pi Pico board, other boards may vary.
|
||||
|
||||
GPIO 4 (pin 6)-> SDA on MPU6050 board
|
||||
GPIO 5 (pin 7)-> SCL on MPU6050 board
|
||||
3.3v (pin 36) -> VCC on MPU6050 board
|
||||
GND (pin 38) -> GND on MPU6050 board
|
||||
*/
|
||||
|
||||
// By default these devices are on bus address 0x68
|
||||
static int addr = 0x68;
|
||||
|
||||
#define I2C_PORT i2c0
|
||||
|
||||
static void mpu6050_reset() {
|
||||
// Two byte reset. First byte register, second byte data
|
||||
// There are a load more options to set up the device in different ways that could be added here
|
||||
uint8_t buf[] = {0x6B, 0x00};
|
||||
i2c_write_blocking(I2C_PORT, addr, buf, 2, false);
|
||||
}
|
||||
|
||||
static void mpu6050_read_raw(int16_t accel[3], int16_t gyro[3], int16_t *temp) {
|
||||
// For this particular device, we send the device the register we want to read
|
||||
// first, then subsequently read from the device. The register is auto incrementing
|
||||
// so we don't need to keep sending the register we want, just the first.
|
||||
|
||||
uint8_t buffer[6];
|
||||
|
||||
// Start reading acceleration registers from register 0x3B for 6 bytes
|
||||
uint8_t val = 0x3B;
|
||||
i2c_write_blocking(I2C_PORT, addr, &val, 1, true); // true to keep master control of bus
|
||||
i2c_read_blocking(I2C_PORT, addr, buffer, 6, false);
|
||||
|
||||
for (int i = 0; i < 3; i++) {
|
||||
accel[i] = (buffer[i * 2] << 8 | buffer[(i * 2) + 1]);
|
||||
}
|
||||
|
||||
// Now gyro data from reg 0x43 for 6 bytes
|
||||
// The register is auto incrementing on each read
|
||||
val = 0x43;
|
||||
i2c_write_blocking(I2C_PORT, addr, &val, 1, true);
|
||||
i2c_read_blocking(I2C_PORT, addr, buffer, 6, false); // False - finished with bus
|
||||
|
||||
for (int i = 0; i < 3; i++) {
|
||||
gyro[i] = (buffer[i * 2] << 8 | buffer[(i * 2) + 1]);;
|
||||
}
|
||||
|
||||
// Now temperature from reg 0x41 for 2 bytes
|
||||
// The register is auto incrementing on each read
|
||||
val = 0x41;
|
||||
i2c_write_blocking(I2C_PORT, addr, &val, 1, true);
|
||||
i2c_read_blocking(I2C_PORT, addr, buffer, 2, false); // False - finished with bus
|
||||
|
||||
*temp = buffer[0] << 8 | buffer[1];
|
||||
}
|
||||
|
||||
int main() {
|
||||
stdio_init_all();
|
||||
|
||||
printf("Hello, MPU6050! Reading raw data from registers...\n");
|
||||
|
||||
// This example will use I2C0 on GPIO4 (SDA) and GPIO5 (SCL) running at 400kHz.
|
||||
i2c_init(I2C_PORT, 400 * 1000);
|
||||
gpio_set_function(4, GPIO_FUNC_I2C);
|
||||
gpio_set_function(5, GPIO_FUNC_I2C);
|
||||
gpio_pull_up(4);
|
||||
gpio_pull_up(5);
|
||||
|
||||
mpu6050_reset();
|
||||
|
||||
int16_t acceleration[3], gyro[3], temp;
|
||||
|
||||
while (1) {
|
||||
mpu6050_read_raw(acceleration, gyro, &temp);
|
||||
|
||||
// These are the raw numbers from the chip, so will need tweaking to be really useful.
|
||||
// See the datasheet for more information
|
||||
printf("Acc. X = %d, Y = %d, Z = %d\n", acceleration[0], acceleration[1], acceleration[2]);
|
||||
printf("Gyro. X = %d, Y = %d, Z = %d\n", gyro[0], gyro[1], gyro[2]);
|
||||
// Temperature is simple so use the datasheet calculation to get deg C.
|
||||
// Note this is chip temperature.
|
||||
printf("Temp. = %f\n", (temp / 340.0) + 36.53);
|
||||
|
||||
sleep_ms(100);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
BIN
i2c/mpu6050_i2c/mpu6050_i2c.fzz
Normal file
BIN
i2c/mpu6050_i2c/mpu6050_i2c.fzz
Normal file
Binary file not shown.
BIN
i2c/mpu6050_i2c/mpu6050_i2c_bb.png
Normal file
BIN
i2c/mpu6050_i2c/mpu6050_i2c_bb.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 223 KiB |
Reference in New Issue
Block a user