I2C external (IOCTL)

Description

This example demonstrates communication with an external 24LC64 EEPROM memory connected to the I2C port of the Red Pitaya using SPCI and API commands. The code below first writes a custom message to the external EEPROM and then reads it back.

Note

The following code works for the 24LC64 EEPROM chip and should be modified for use with other external I2C devices. The lower three bits of the 24LC64 EEPROM HW address are hardware defined by the pins on the PCB. In addition, the first two bytes transmitted correspond to the target address in the EEPROM. Please refer to the datasheet of your I2C device for the correct addressing and communication protocol.

Required hardware

  • Red Pitaya

../../../_images/RedPitaya_general.png

Required software

  • 2.00-23 or higher OS

Note

This code is written for 2.00-23 or higher OS. For older OS versions, please check when specific commands were released (a note is added to each command introduced in 2.00 or higher verisons).

SCPI Code Examples

Code - MATLAB®

%% Define Red Pitaya as TCP/IP object
clc
close all
IP = 'rp-f0a235.local';           % IP of your Red Pitaya
port = 5000;
RP = tcpclient(IP, port);

%% Variables
% EEPROM 24LC64 DATA
dev_addr = 0b1010110;
eeprom_size = 8192;
page_size = 32;
offset = uint16(0x0000);
path ="/dev/i2c-0";

txt = uint8('Pitaya Red');      % Max 16 characters long

%% Open connection with your Red Pitaya
RP.ByteOrder = 'big-endian';
configureTerminator(RP,'CR/LF');
flush(RP);
fprintf('Start\n');


%% Configure I2C communication
writeline(RP, append('I2C:DEV', num2str(dev_addr), ' "', path, '"'));
writeline(RP, 'I2C:FMODE ON');

% Communication with external 24LC64 EEPROM, for other devices, please refer to the device datasheet
buf = zeros(1, length(txt)+2, 'uint8');

buf(1) = bitshift(offset, -8);              % 24LC64 address byte 1
buf(2) = bitand(offset, uint16(0xFF));      % 24LC64 address byte 2
buf(3:length(txt)+2) = txt                  % Data to write

writeline(RP, append('I2C:IOctl:Write:Buffer', num2str(length(buf)), ' ', strjoin(compose('%d',buf),",")))

pause(0.01);
% Reading data
writeline(RP, append('I2C:IOctl:Write:Buffer2 ', strjoin(compose('%d',buf(1:2)),",")))
data = writeread(RP, append('I2C:IOctl:Read:Buffer', num2str(length(txt)), '?'));
data = str2double(split(strip(strip(data, '{'), '}'), ','))

%% Close the interface
fprintf("Program End\n")
clear RP;

Code - Python

#!/usr/bin/env python3
"""External I2C 24LC64 communication example"""

import time
import numpy as np
import redpitaya_scpi as scpi

### EEPROM 24LC64 DATA ###
dev_addr=0b1010110
eeprom_size=8192
page_size=32
offset=0x0000
path="/dev/i2c-0"

txt = np.frombuffer(b'Pitaya Red', dtype=np.uint8)    # Max 16 characters long


IP = 'rp-f0a235.local'     # IP Test OS Red Pitaya
rp = scpi.scpi(IP)

# Configure I2C communication
rp.tx_txt(f"I2C:DEV{dev_addr} \"{path}\"")
rp.check_error()
rp.tx_txt("I2C:FMODE ON")
rp.check_error()

# Communication with external 24LC64 EEPROM, for other devices, please refer to the device datasheet
buf = np.zeros((len(txt)+2), dtype=np.uint8)
buf[0]=offset >> 8      # 24LC64 address byte 1
buf[1]=offset & 0xFF    # 24LC64 address byte 2
buf[2:]=txt             # Data to write
rp.tx_txt(f"I2C:IOctl:Write:Buffer{len(buf)} {np.array2string(buf, separator=',').strip(" []").replace(" ","")}")
rp.check_error()

time.sleep(0.01)

print("Reading data")
rp.tx_txt(f"I2C:IOctl:Write:Buffer{2} {np.array2string(buf[0:2], separator=',').strip(" []").replace(" ","")}")
data = rp.txrx_txt(f"I2C:IOctl:Read:Buffer{len(buf)}?")
data = np.array(list(map(int, data.strip("{}").split(","))), dtype=np.uint8)
data_string=''.join([chr(i) for i in data])
rp.check_error()

print(f"{data_string}")

rp.close()

Note

The Python functions are accessible with the latest version of the redpitaya_scpi.py document available on our :github:`GitHub `. The functions represent a quality-of-life improvement as they combine the SCPI commands in an optimal order. The code should function at approximately the same speed without them.

For further information on functions please consult the redpitaya_scpi.py code.

API Code Examples

Note

The API code examples don’t require the use of the SCPI server. Instead, the code should be compiled and executed on the Red Pitaya itself (inside Linux OS). Instructions on how to compile the code and other useful information are here.

Code - C++

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "rp_hw.h"
#include "rp_hw-calib.h"


#define EEPROM_ADDR 0b1010110           // 24LC64 address
#define EEPROM_SIZE 8192                // 64K EEPROM
#define PAGE_SIZE 32                    // EEPROM page size

int main(int argc, char *argv[]){

    int address = 0;
    int res = 0;

    uint8_t buf[PAGE_SIZE+2];           // max write size is page size + 2 address bytes
    int offset = 0x0000;                // address offset
    uint8_t text[] = "123 45678";       //  Test data
    int text_len = sizeof(text)/sizeof(uint8_t);        // number of bytes to read/write

    // This example shows how to work with external EEPROM via I2C

    res = rp_I2C_InitDevice("/dev/i2c-0", EEPROM_ADDR); // Init i2c api.
    printf("Init result: %d\n",res);

    res = rp_I2C_getDevAddress(&address);
    printf("Dev address: %d\n", address);
    printf("Get addr result: %d\n",res);

    res = rp_I2C_setForceMode(true);                    // Set force mode.
    printf("Set force mode: %d\n",res);

    // Write data to EEPROM
    buf[0] = offset >> 8;       // high byte of address
    buf[1] = offset & 0xFF;     // low byte of address
    for(int i = 0; i < text_len; i++){
        buf[i+2] = text[i];     // data to be written
    }

    printf("Written string: %s\n", buf);
    res = rp_I2C_IOCTL_WriteBuffer(buf, text_len+2);    // Write position for reading.
    printf("Write text res: %d\n",res);
    usleep(10000);

    // Read data from EEPROM

    // Change read/write pointer to start of written data
    buf[0] = offset >> 8;       // high byte of address
    buf[1] = offset & 0xFF;     // low byte of address

    res = rp_I2C_IOCTL_WriteBuffer(buf, 2);             // Write position for reading.
    usleep(10000);

    memset(buf,0,PAGE_SIZE+2);
    res = rp_I2C_IOCTL_ReadBuffer(buf, text_len);       // Read 1 byte from I2C
    printf("Read text res: %d\n",res);
    printf("Read string: %s\n", buf);

    printf("End");

    return 0;
}

Code - Python

#!/usr/bin/python3
import time
import rp_hw

EEPROM_ADDR = 0b1010110           # 24LC64 address
EEPROM_SIZE = 8192                # 64K EEPROM
PAGE_SIZE = 32                    # EEPROM page size

address = 0
res = 0

# Message
data = list("TEST string")
# Convert data to integer array corresponding to ASCII values
data_int = [ord(char) for char in data]
data_size = len(data_int)
offset = 0x0000                                # EEPROM address offset

# This example shows how to work with external EEPROM via I2C
res = rp_hw.rp_I2C_InitDevice("/dev/i2c-0", EEPROM_ADDR)      # Init i2c api.
print(f"InitDevice: {'success' if not res else 'fail'}")

rp_hw.rp_I2C_setForceMode(True)                         # Set force mode.
res = rp_hw.rp_I2C_getDevAddress()
print(f"Device address: {res[1]}")

# Prepare data for sending
rx_buff = rp_hw.Buffer(PAGE_SIZE+2)
rx_buff[0] = offset >> 8                                # high byte of address
rx_buff[1] = offset & 0xFF                              # low byte of address

for i in range(data_size):
    rx_buff[i+2] = data_int[i]

# Write data to EEPROM
res = rp_hw.rp_I2C_IOCTL_WriteBuffer(rx_buff, data_size+2)
print("Data written to EEPROM")
print(f"Write res: {res}\n")
time.sleep(5e3/1e6) # 5 ms

# Change read/write pointer to start of written data
rx_buff[0] = offset >> 8                                # high byte of address
rx_buff[1] = offset & 0xFF                              # low byte of address

rp_hw.rp_I2C_IOCTL_WriteBuffer(rx_buff, 2)
print(f"Change address pointer to 0x{offset:02x}")
time.sleep(1e3/1e6) # 1 ms

# Read data from EEPROM
res = rp_hw.rp_I2C_IOCTL_ReadBuffer(rx_buff, data_size+2)
print(f"Read res: {res}")
data_read = [chr(rx_buff[i]) for i in range(data_size)]
print(f"Read data: {data_read}\n")

# Change read/write pointer to end of written data
offset = data_size
rx_buff[0] = offset >> 8                                # high byte of address
rx_buff[1] = offset & 0xFF                              # low byte of address
rp_hw.rp_I2C_IOCTL_WriteBuffer(rx_buff, 2)
print(f"Change address pointer to 0x{offset:02x}")

# Read data after the written data
res = rp_hw.rp_I2C_IOCTL_ReadBuffer(rx_buff, data_size+2)
print(f"Read res: {res}")
data_read = [chr(rx_buff[i]) for i in range(data_size)]
print(f"Read data: {data_read}\n")