SPI on linux(raspberry PI) using spidev - arrays

I'm trying to use SPI on Raspberry PI using spidev and his test code as skeleton for my own. I have a problem with table size. My table has different size before I pass it to transfer function i.e. my table has 3 elements, inside function it has 4. Here is my code:
// spi.cpp : Defines the entry point for the console application.
//
#include <stdint.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/types.h>
#include <linux/spi/spidev.h>
#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
static const char *device = "/dev/spidev0.0";
static uint8_t mode;
static uint8_t bits = 8;
static uint32_t speed = 1000000;
static uint16_t delay;
//this function gives problems with diffrent size of array
static void transfer(int fd, uint8_t tx[])
{
printf("transfer1");
printf(" rozmiar tab=%d ", ARRAY_SIZE(tx));
int ret;
uint8_t rx[ARRAY_SIZE(tx)] = { 0, };
struct spi_ioc_transfer tr = {
.tx_buf = (unsigned long)tx,
.rx_buf = (unsigned long)rx,
.len = 3,
.delay_usecs = delay,
.speed_hz = speed,
.bits_per_word = bits,
};
ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);
for (ret = 0; ret < ARRAY_SIZE(tx); ret++) {
if (!(ret % 6))
puts("");
printf("%d. %.2X ", ret,rx[ret]);
}
puts("");
}
int main(int argc, char *argv[])
{
int ret = 0;
int fd;
fd = open(device, O_RDWR);
/*
* spi mode
*/
ret = ioctl(fd, SPI_IOC_WR_MODE, &mode);
ret = ioctl(fd, SPI_IOC_RD_MODE, &mode);
/*
* bits per word
*/
ret = ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits);
ret = ioctl(fd, SPI_IOC_RD_BITS_PER_WORD, &bits);
/*
* max speed hz
*/
ret = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed);
ret = ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed);
printf("spi mode: %d\n", mode);
printf("bits per word: %d\n", bits);
printf("max speed: %d Hz (%d KHz)\n", speed, speed / 1000);
uint8_t tx1[] = {
0x0, 0x1b, 0xa5
};
//here I'm passing table to function
transfer(fd, tx1);
uint8_t tx2[] = {
0x0, 0x33, 0x30, 0x01, 0x02
};
printf(" %d. ", ARRAY_SIZE(tx2));
transfer(fd, tx2);
uint8_t tx3[] = {
0x0, 0x52, 0x90
};
transfer(fd, tx3);
uint8_t tx4[] = {
0x80, 0x60
};
printf(" %d. ", ARRAY_SIZE(tx4));
transfer(fd, tx4);
close(fd);
return ret;
}

An array sent as a parameter to a function is treated as a pointer. Your ARRAY_SIZE(a) is roughly expanded to (sizeof(uint8_t*) / sizeof(uint8_t)), which equals 4 on 32-bit platform.
You should explicitly pass array size as a 3rd parameter:
void transfer(int fd, const uint8_t *tx, size_t size) { ... }
Then, you can use your macro to properly calculate array size:
transfer(fd, tx1, ARRAY_SIZE(tx1));
If tx is not being modified inside transfer(), it is a matter of good taste to make it const.

Related

Linux Driver Programming: Problem with usb_control_msg

Short Version
I want to write a Linux Driver for a custom USB device. Before writing the driver I used libusb-1.0 to test the device. With the following function call, I could read out a uin16_t value from the device:
status = libusb_control_transfer(handle, /* Device Handle */
0x80, /* bRequestType */
0x10, /* bRequest */
value, /* wValue */
0x0, /* wIndex */
((uint8_t *) &value), /* data */
2, /* wLength */
100); /* timeout */
After this call, I got a new value in the value variable.
Now I want to accomplish the same call in my Driver. I have tried the following in the probe function of my USB driver:
status = usb_control_msg(data->udev, usb_rcvctrlpipe(data->udev, 0), 0x10, USB_DIR_IN, 0, 0, (u8*) &my_data, 2, 100);
All I get is the return value -11 and on my device I don't see anything.
The only thing I am doing before this call, is calling data->udev = interface_to_usbdev(intf); to get the USB device from my interface.
Does anyone know, if I am missing something or if I am doing something wrong?
Long version
I want to learn how to write USB Drivers in Linux. As a DUT for which I can write a driver, I choose a Raspberry Pi Pico and the dev_lowlevel USB example. I adapt the code a little bit, so I can use a control transfer with bRequest 0x10 and bRequestType 0x0 (USB_DIR_OUT) to turn the Pico's onboard LED on or off and a control transfer with bRequest 0x10 and bRequestType 0x80 (USB_DIR_IN) to read back the current value of the LED.
With a user space program and the following code I can read out the value of the LED and turn it on or off:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <libusb-1.0/libusb.h>
#define VID 0x0000
#define DID 0x0001
int main(int argc, char **argv) {
int status, len;
libusb_device_handle *handle = NULL;
/* Init Libusb */
status = libusb_init(NULL);
if(status < 0) {
printf("Error init USB!\n");
return status;
}
handle = libusb_open_device_with_vid_pid(NULL, VID, DID);
if(!handle) {
printf("No device found with %04x:%04x\n", VID, DID);
libusb_exit(NULL);
return -1;
}
if(argc > 1)
value = atoi(argv[1]);
else {
/* Do control transfer */
status = libusb_control_transfer(handle, /* Device Handle */
0x80, /* bRequestType */
0x10, /* bRequest */
value, /* wValue */
0x0, /* wIndex */
((uint8_t *) &value), /* data */
2, /* wLength */
100); /* timeout */
if(status < 0) {
printf("Error during control transfer!\n");
libusb_close(handle);
libusb_exit(NULL);
return -1;
}
printf("Got: %d\n", value);
value = (value + 1) & 0x1;
}
/* Do control transfer */
status = libusb_control_transfer(handle, 0x0, 0x10, value, 0x0, NULL, 0, 100);
if(status < 0) {
printf("Error during control transfer!\n");
libusb_close(handle);
libusb_exit(NULL);
return -1;
}
libusb_close(handle);
libusb_exit(NULL);
return 0;
}
Now I want to control my device over a USB Driver. Here is what I got already:
#include <linux/module.h>
#include <linux/init.h>
#include <linux/usb.h>
#include <linux/slab.h>
/* Meta Information */
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Johannes 4 GNU/Linux");
MODULE_DESCRIPTION("Driver for my custom RPi Pico USB device");
struct pico_usb {
struct usb_device *udev;
};
#define PICO_VID 0x0000
#define PICO_PID 0x0001
static struct usb_device_id pico_usb_table [] = {
{ USB_DEVICE(PICO_VID, PICO_PID) },
{},
};
MODULE_DEVICE_TABLE(usb, pico_usb_table);
static int pico_usb_probe(struct usb_interface *intf, const struct usb_device_id *id) {
struct pico_usb *data;
int status;
int my_data;
printk("pico_usb_drv - Now I am in the Probe function!\n");
data = kzalloc(sizeof(struct pico_usb), GFP_KERNEL);
if(!data) {
printk("pico_usb_drv - Out of memory\n");
return -ENOMEM;
}
data->udev = interface_to_usbdev(intf);
usb_set_intfdata(intf, data);
/* Turn the LED on */
status = usb_control_msg(data->udev, usb_sndctrlpipe(data->udev, 0), 0x10, USB_DIR_OUT, 1, 0, 0, 0, 100);
/* Read LED state */
printk("pico_usb_drv - status USB_DIR_OUT: %d\n", status);
status = usb_control_msg(data->udev, usb_rcvctrlpipe(data->udev, 0), 0x10, USB_DIR_IN, 0, 0, (u8*) &my_data, 2, 100);
printk("pico_usb_drv - status USB_DIR_IN: %d\n", status);
return 0;
}
static void pico_usb_disconnect(struct usb_interface *intf) {
struct pico_usb *data;
printk("pico_usb_drv - Now I am in the Disconnect function!\n");
data = usb_get_intfdata(intf);
kfree(data);
}
static struct usb_driver pico_usb_driver = {
//.owner = THIS_MODULE,
.name = "pico_usb",
.id_table = pico_usb_table,
.probe = pico_usb_probe,
.disconnect = pico_usb_disconnect,
};
/**
* #brief This function is called, when the module is loaded into the kernel
*/
static int __init pico_usb_init(void) {
int result;
printk("pico_usb_drv - Registering the PICO USB device\n");
result = usb_register(&pico_usb_driver);
if(result) {
printk("pico_usb_drv - Error registering the PICO USB device\n");
return -result;
}
return 0;
}
/**
* #brief This function is called, when the module is removed from the kernel
*/
static void __exit pcio_usb_exit(void) {
printk("pico_usb_drv - Unregistering the PICO USB device\n");
usb_deregister(&pico_usb_driver);
}
module_init(pico_usb_init);
module_exit(pcio_usb_exit);
The first control message works and my LED is turned on. But the second control message doesn't do anything, but gives me the error code -11 back.
Does anyone know, if I am missing something or if I am doing something wrong?
Ok, I found the solution. Instead of usb_control_msg I use usb_control_msg_recv now and everything works just fine.
usb_control_msg_recv takes one more argument:
int usb_control_msg_recv(struct usb_device *dev, __u8 endpoint, __u8 request, __u8 requesttype, __u16 value, __u16 index, void *driver_data, __u16 size, int timeout, gfp_t memflags)
As I pass the pointer to a variable and don't want to allocate memory dynamically, I set the memflags argument to 0.

STM32 LwIP netconn_write problem transmitting structs

I am using LwIP stack with FreeRTOS in STM32F407Discovery board as TCP Client and I have a Linux computer as TCP Server. I faced a problem during transmission of a struct array, say struct EncoderData Encoder[2], through netconn API.
The thing is, when I print the elements of the struct array to Serial Terminal (with UART) the data stored in the struct array is correctly shown. However when I send the structs through netconn socket, the elements of the first struct, i.e. Encoder[0] is received correctly, whereas Encoder[1] is received as all zeroes.
Expected output in the Server side,
Encoder[0] ---> 0xAA 0x07 0x00 0x52 0x12 0xDC 0xAB 0xFA
Encoder[1] ---> 0xAA 0x07 0x01 0x52 0x42 0xBF 0xAA 0xFA
Resulting problematic output in the Server side
Encoder[0] ---> 0xAA 0x07 0x00 0x52 0x12 0xDC 0xAB 0xFA
Encoder[1] ---> 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
Below, I am sharing both the server and the client side code, I would appreciate if you could help me out identifying the problem.
Server.c -- Linux Computer
#define MAX 9
#define PORT 8080
#define SA struct sockaddr
#define NUM_OF_ENCODERS 2
#define PREAMBLE 0xAA
#define LENGTH 0x07
#define CRC 0xFA
struct EncoderData {
volatile uint8_t encoderID;
volatile uint8_t byte0;
volatile uint8_t byte1;
volatile uint8_t byte2;
volatile uint8_t byte3;
volatile uint8_t byte4;
volatile uint32_t singleTurnValue;
volatile uint16_t multiTurnValue;
volatile uint16_t prevMultiTurnValue;
volatile uint8_t direction;
volatile float angle;
};
struct EncoderData Encoder[NUM_OF_ENCODERS];
// This function is called inside int main()
void func(int sockfd)
{
uint8_t buff[MAX];
uint32_t singleTurnValue = 0;
float angle = 0.0;
uint8_t channel;
uint8_t encoderID;
// infinite loop to read data continuously
for (;;) {
bzero(buff, MAX);
// read the message from client and copy it in buffer
read(sockfd, buff, sizeof(buff));
if(buff[0] == PREAMBLE && buff[1] == LENGTH && buff[8] == CRC)
{
encoderID = buff[2];
Encoder[encoderID].encoderID = encoderID;
Encoder[encoderID].byte0 = (uint8_t)buff[3];
Encoder[encoderID].byte1 = (uint8_t)buff[4];
Encoder[encoderID].byte2 = (uint8_t)buff[5];
Encoder[encoderID].byte3 = (uint8_t)buff[6];
Encoder[encoderID].byte4 = (uint8_t)buff[7];
Encoder[encoderID].singleTurnValue = (uint32_t)((buff[5] << 16)|(buff[6] << 8)|(buff[7]));
Encoder[encoderID].multiTurnValue = (uint16_t)((buff[3] << 8)|(buff[4]));
//printf("%d\n", encoderID);
bzero(buff, MAX);
}
// Here I print the struct elements, below printf shows data correctly
printf("0x%X 0x%X 0x%X 0x%X 0x%X 0x%X\t\t",
Encoder[0].encoderID, Encoder[0].byte0, Encoder[0].byte1,
Encoder[0].byte2, Encoder[0].byte3, Encoder[0].byte4);
// However below printf results in only zeroes
printf("0x%X 0x%X 0x%X 0x%X 0x%X 0x%X\n",
Encoder[1].encoderID, Encoder[1].byte0, Encoder[1].byte1,
Encoder[1].byte2, Encoder[1].byte3, Encoder[1].byte4);
}
}
Client.c -- STM32F407Discovery
#define NUM_OF_ENCODERS 2
struct EncoderData Encoder[NUM_OF_ENCODERS];
void Encoder_Process(void)
{
//float angle = 0.0;
uint64_t encoderRawValue = 0;
uint32_t singleTurnValue = 0;
uint8_t channel = 0;
for(channel = 0; channel < NUM_OF_ENCODERS; channel++)
{
selectChannel(channel);
encoderRawValue = readEncoder();
singleTurnValue = getSingleTurn(encoderRawValue);
angle = calculateMotorAngle(singleTurnValue);
Encoder[channel].preamble = 0xAA;
Encoder[channel].length = 0x07;
Encoder[channel].encoderID = channel;
Encoder[channel].byte0 = (uint8_t)((encoderRawValue >> 32) & 0xFF);
Encoder[channel].byte1 = (uint8_t)((encoderRawValue >> 24) & 0xFF);
Encoder[channel].byte2 = (uint8_t)((encoderRawValue >> 16) & 0xFF);
Encoder[channel].byte3 = (uint8_t)((encoderRawValue >> 8) & 0xFF);
Encoder[channel].byte4 = (uint8_t)((encoderRawValue ) & 0xFF);
Encoder[channel].crc = 0xFA;
}
}
// Convert Encoder struct into buffer
uint8_t* prepareEncoderData(struct EncoderData enc)
{
static uint8_t buffer[9];
memset(buffer, '\0', 9);
buffer[0] = enc.preamble;
buffer[1] = enc.length;
buffer[2] = enc.encoderID;
buffer[3] = enc.byte0;
buffer[4] = enc.byte1;
buffer[5] = enc.byte2;
buffer[6] = enc.byte3;
buffer[7] = enc.byte4;
buffer[8] = enc.crc;
return buffer;
}
static void tcp_client_netconn_thread(void *arg)
{
struct netconn *conn; //, *newconn;
struct ip_addr remoteipaddr, localipaddr;
err_t err1, err2;
// portCHAR pagehits[100] = {0};
uint8_t channels;
uint8_t *transmitBuffer;
IP4_ADDR(&remoteipaddr, DEST_IP_ADDR0, DEST_IP_ADDR1, DEST_IP_ADDR2, DEST_IP_ADDR3);
IP4_ADDR(&localipaddr, IP_ADDR0, IP_ADDR1, IP_ADDR2, IP_ADDR3);
/* Create a new TCP connection handle */
conn = netconn_new(NETCONN_TCP);
if (conn!= NULL)
{
err1 = netconn_bind(conn, &localipaddr, PORT_NUMBER);
err2 = netconn_connect(conn, &remoteipaddr, PORT_NUMBER);
if (err1 == ERR_OK && err2 == ERR_OK)
{
printf("STM32F4 connected to the server!\n");
while(1)
{
for(channels = 0; channels < NUM_OF_ENCODERS; channels++)
{
Encoder_Process();
transmitBuffer = prepareEncoderData(Encoder[channels]);
netconn_write(conn, transmitBuffer, strlen((char*)transmitBuffer), NETCONN_COPY);
}
vTaskDelay(10);
//netconn_delete(newconn);
}
}
else
{
printf("can not bind netconn");
printf("\terr code: %d", err1);
printf("\terr code: %d\n", err2);
}
}
else
{
printf("can not create netconn");
}
}

Initialising LCD eadip203-6 using functions over Beaglebone Black SPI

I am trying to write down the functions for the LCD initialisation with the LCD screen eadip203-6 using SPI on beaglebone black. I am facing some problems as I am trying to execute the functions, initially the screen gets stuck, then if I comment the above functions and see what happens the cursor still blinks. I am trying to do this from page number 29,30 and 33,34,35,36,37,38,39,40 of the data sheet. I have not written all the 16 functions. But written a few of the starting ones.Now as soon as I execute the last two functions from the above code the screen goes blank. Can you please tell me where am I going wrong in this? Also can you please tell me about the CGRAM,SEGRAM, DDRAM and the busy flag.
#include <stdint.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/types.h>
#include <linux/spi/spidev.h>
#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
static void transfer(int fd, uint16_t* tx, uint8_t cs);
void init_display(int fd);
void clear_display_func(int fd);
void return_home_func(int fd);
void power_mode_func(int fd);
void entry_mode_set_func(int fd);
void display_on_off_func(int fd);
void extended_function_set_func(int fd);
void cursor_display_shift_bias_func(int fd);
static void pabort(const char *s)
{
perror(s);
abort();
}
static const char *device = "/dev/spidev2.1";
static uint8_t mode=3;
static uint8_t bits = 8;
static uint32_t speed = 40000;
static uint16_t delay;
void clear_display_func(int fd)
{
int ret;
uint16_t clear_display[]={0xF8,0x80,0x00};
for(ret=0; ret<3; ret++)
{
transfer(fd,&clear_display[ret],0);
usleep(2000);
}
}
void return_home_func(int fd)
{
int ret;
uint16_t return_home[]={0xF8,0x40,0x00};
for(ret=0; ret<3; ret++)
{
transfer(fd,&return_home[ret],0);
usleep(2000);
}
}
void power_mode_func(int fd)
{
int ret;
uint16_t power_mode[]={0xF8,0xC0,0x00};
for(ret=0; ret<3; ret++)
{
transfer(fd,&power_mode[ret],0);
usleep(2000);
}
}
void entry_mode_set_func(int fd)
{
int ret;
uint16_t entry_mode_set[]={0xF8,0xE0,0x00,
0xF8,0x60,0x00};
for(ret=0; ret<6; ret++)
{
transfer(fd,&entry_mode_set[ret],0);
usleep(2000);
}
}
void display_on_off_func(int fd)
{
int ret;
uint16_t display_on_off[]={0xF8,0xF0,0x00};
for(ret=0; ret<3; ret++)
{
transfer(fd,&display_on_off[ret],0);
usleep(2000);
}
}
void extended_function_set_func(int fd)
{
int ret;
uint16_t extended_function_set[]={0xF8,0xD0,0x00};
for(ret=0; ret<3; ret++)
{
transfer(fd,&extended_function_set[ret],0);
usleep(2000);
}
}
void cursor_display_shift_bias_func(int fd)
{
int ret;
uint16_t cursor_display_shift_bias[]={0xF8,0x50,0x80};
for(ret=0; ret<3; ret++)
{
transfer(fd,&cursor_display_shift_bias[ret],0);
usleep(2000);
}
}
static void transfer(int fd, uint16_t* tx, uint8_t cs){
int ret;
uint16_t rx[ARRAY_SIZE(tx)] = {0, };
struct spi_ioc_transfer tr = {
.tx_buf = (unsigned long)tx,
.rx_buf = 0,
.len = 1,
.delay_usecs = delay,
.speed_hz = speed,
.bits_per_word = bits,
.cs_change=cs,
};
printf("%u", cs);
ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);
if (ret < 1)
pabort("can't send spi message");
puts("");
}
static void print_usage(const char *prog)
{
printf("Usage: %s [-DsbdlHOLC3]\n", prog);
puts(" -D --device device to use (default /dev/spidev1.1)\n"
" -s --speed max speed (Hz)\n"
" -d --delay delay (usec)\n"
" -b --bpw bits per word \n"
" -l --loop loopback\n"
" -H --cpha clock phase\n"
" -O --cpol clock polarity\n"
" -L --lsb least significant bit first\n"
" -C --cs-high chip select active high\n"
" -3 --3wire SI/SO signals shared\n");
exit(1);
}
static void parse_opts(int argc, char *argv[])
{
while (1) {
static const struct option lopts[] = {
{ "device", 1, 0, 'D' },
{ "speed", 1, 0, 's' },
{ "delay", 1, 0, 'd' },
{ "bpw", 1, 0, 'b' },
{ "loop", 0, 0, 'l' },
{ "cpha", 0, 0, 'H' },
{ "cpol", 0, 0, 'O' },
{ "lsb", 0, 0, 'L' },
{ "cs-high", 0, 0, 'C' },
{ "3wire", 0, 0, '3' },
{ "no-cs", 0, 0, 'N' },
{ "ready", 0, 0, 'R' },
{ NULL, 0, 0, 0 },
};
int c;
c = getopt_long(argc, argv, "D:s:d:b:lHOLC3NR", lopts,
NULL);
if (c == -1)
break;
switch (c) {
case 'D':
device = optarg;
break;
case 's':
speed = atoi(optarg);
break;
case 'd':
delay = atoi(optarg);
break;
case 'b':
bits = atoi(optarg);
break;
case 'l':
mode |= SPI_LOOP;
break;
case 'H':
mode |= SPI_CPHA;
break;
case 'O':
mode |= SPI_CPOL;
break;
case 'L':
mode |= SPI_LSB_FIRST;
break;
case 'C':
mode |= SPI_CS_HIGH;
break;
case '3':
mode |= SPI_3WIRE;
break;
case 'N':
mode |= SPI_NO_CS;
break;
case 'R':
mode |= SPI_READY;
break;
default:
print_usage(argv[0]);
break;
}
}
}
int main(int argc, char *argv[])
{
int ret = 0;
int fd;
parse_opts(argc, argv);
fd = open(device, O_RDWR);
if (fd < 0)
pabort("can't open device");
/*
* spi mode
*/
ret = ioctl(fd, SPI_IOC_WR_MODE, &mode);
if (ret == -1)
pabort("can't set spi mode");
ret = ioctl(fd, SPI_IOC_RD_MODE, &mode);
if (ret == -1)
pabort("can't get spi mode");
/*
* bits per word
*/
ret = ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits);
if (ret == -1)
pabort("can't set bits per word");
ret = ioctl(fd, SPI_IOC_RD_BITS_PER_WORD, &bits);
if (ret == -1)
pabort("can't get bits per word");
/*
* max speed hz
*/
ret = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed);
if (ret == -1)
pabort("can't set max speed hz");
ret = ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed);
if (ret == -1)
pabort("can't get max speed hz");
printf("spi mode: %d\n", mode);
printf("bits per word: %d\n", bits);
printf("max speed: %d Hz (%d KHz)\n", speed, speed/1000);
init_display(fd);
usleep(20000);
clear_display_func(fd);
usleep(20000);
return_home_func(fd);
usleep(20000);
power_mode_func(fd);
usleep(20000);
entry_mode_set_func(fd);
usleep(20000);
display_on_off_func(fd);
usleep(20000);
extended_function_set(fd);
usleep(20000);
cursor_display_shift_bias_func(int fd);
usleep(20000);
close(fd);
return ret;
}

trying to read light sensor using i2c & bcm2835 on RPI - TSL2561

My brother and I have been trying to get this working for days now and we just can't figure out what we are doing wrong, we could really use some help please!
What we're trying to accomplish is reading in data from a light sensor on an RPI expansion board through our own program written in C, using the BCM2835 library.
This is the light sensor we are using: TSL2561
https://cdn-shop.adafruit.com/datasheets/TSL2561.pdf
We are using a raspberry pi B+ model with Raspbian installed on it (through noobs).
This is the C library we are using:
http://www.airspayce.com/mikem/bcm2835/
I activated I2c through the raspian configuration.
and I detected the light sensor through i2ctools and it shows up correctly with adress 0x29.
We get 0 values back with our reads, and we tested our commands with an osciloscope and it seems he does ACK the write commands. he just doesn't send anything back...
Can someone please help us ?
#include <bcm2835.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
uint16_t clk_div = BCM2835_I2C_CLOCK_DIVIDER_148;
uint8_t slave_address = 0x29; //0101001 - this is the sensor address
uint64_t delay = 70000;
int main(int argc, char **argv)
{
/*
DATA0LOW Ch 7:0 ADC channel 0 lower byte
DATA0HIGH Dh 7:0 ADC channel 0 upper byte
*/
char buffer[10]={0};
char addr;
uint16_t data;
uint8_t data2;
int i =0;
char writeBuff[1] = {0x8C}; ////Address the Ch0 lower data register
char readBuff[10];
char writeBuff2[2] = {0x8D}; ////Address the Ch0 upper data register
char readBuff2[10];
char *wb_ptr,*r_ptr,*wb_ptr2,*r_ptr2;
wb_ptr = writeBuff;
wb_ptr2 = writeBuff2;
r_ptr = readBuff;
r_ptr2 = readBuff2;
printf("Running ... \n");
bcm2835_init():
bcm2835_i2c_begin();
bcm2835_i2c_setSlaveAddress(slave_address); //0x29
printf("Clock divider set to: %d\n", clk_div);
printf("Slave address set to: %d or %X\n",slave_address,slave_address);
//needed according to datasheet to read although unsure if it needs to be sent in two writes or in one ? 0x83 instead of 0x80 + 0x03 ?
bcm2835_i2c_write(0x80, 1); //command register
bcm2835_i2c_write(0x03, 1); //command itself
bcm2835_delayMicroseconds(delay);
//--------------------------
while (1)
{
printf("reading data from light sensor\n");
bcm2835_i2c_write(wb_ptr, 1); // 0x8C
bcm2835_delayMicroseconds(delay);
data = bcm2835_i2c_read(readBuff,1);
bcm2835_delayMicroseconds(delay);
printf("Read Result 1 = %d\n", data);
bcm2835_i2c_write(wb_ptr2, 1); //0x8D
bcm2835_delayMicroseconds(delay);
data2 = bcm2835_i2c_read(readBuff2,1);
bcm2835_delayMicroseconds(delay);
printf("Read Result 2 = %d\n", data);
bcm2835_delay(1000);
}
bcm2835_i2c_end();
bcm2835_close();
printf("... done\n");
return 0;
}
This is a Quick edit
#include <bcm2835.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
uint16_t clk_div = BCM2835_I2C_CLOCK_DIVIDER_148;
uint8_t slave_address = 0x29; //0101001 - this is the sensor address
uint64_t delay = 70000;
int main(int argc, char **argv)
{
/*
DATA0LOW Ch 7:0 ADC channel 0 lower byte
DATA0HIGH Dh 7:0 ADC channel 0 upper byte
*/
/*
enum bcm2835I2CReasonCodes { BCM2835_I2C_REASON_OK = 0x00, BCM2835_I2C_REASON_ERROR_NACK = 0x01, BCM2835_I2C_REASON_ERROR_CLKT = 0x02, BCM2835_I2C_REASON_ERROR_DATA = 0x04 }
*/
char buffer[10]={0};
char addr;
uint16_t data;
uint8_t data2;
uint8_t error = 0xff;
int i =0;
char writeBuff[1] = {0x8C}; ////Address the Ch0 lower data register
char readBuff[10];
char writeBuff2[2] = {0x8D}; ////Address the Ch0 upper data register
char readBuff2[10];
char writeBuff3[2] = {0x80};
char writeBuff4[2] = {0x03};
char *wb_ptr,*r_ptr,*wb_ptr2,*r_ptr2,*r_ptr3,*r_ptr4;
wb_ptr = writeBuff;
wb_ptr2 = writeBuff2;
r_ptr = readBuff;
r_ptr2 = readBuff2;
r_ptr3 = writeBuff3;
r_ptr4 = writeBuff4;
printf("Running ... \n");
bcm2835_init();
bcm2835_i2c_begin();
bcm2835_i2c_setSlaveAddress(slave_address); //0x29
printf("Clock divider set to: %d\n", clk_div);
printf("Slave address set to: %d or %X\n",slave_address,slave_address);
//needed according to datasheet to read although unsure if it needs to be sent in two writes or in one ? 0x83 instead of 0x80 + 0x03 ?
bcm2835_i2c_write(r_ptr3, sizeof(r_ptr3)); //command register
bcm2835_i2c_write(r_ptr4, sizeof(r_ptr4)); //command itself
bcm2835_delayMicroseconds(delay);
//--------------------------
// Blink
while (1)
{
printf("reading data from light sensor\n");
error = bcm2835_i2c_write(wb_ptr, sizeof(wb_ptr)); // 0x8C
bcm2835_delayMicroseconds(delay);
data = bcm2835_i2c_read(readBuff,sizeof(readBuff));
bcm2835_delayMicroseconds(delay);
printf("readbuff1 = 0x%02X \n",readBuff);
printf("error result = 0x%02X\n", error);
printf("Read Result 1 = 0x%02X\n", data);
error = bcm2835_i2c_write(wb_ptr2, sizeof(wb_ptr2)); //0x8D
bcm2835_delayMicroseconds(delay);
data2 = bcm2835_i2c_read(readBuff2,sizeof(readBuff2));
bcm2835_delayMicroseconds(delay);
printf("readbuff2 = 0x%02X \n",readBuff2);
printf("error result = 0x%02X\n", error);
printf("Read Result 2 = 0x%02X\n", data2);
bcm2835_delay(1000);
}
bcm2835_i2c_end();
bcm2835_close();
printf("... done\n");
return 0;
}
I managed to fix it, I had several problems , one of which was that I was adressing the wrong adress to send commands, it has to be 0xa0 instead of 0x80.
#include <bcm2835.h>
#include <stdio.h>
int main(void)
{
/*
DATA0LOW Ch 7:0 ADC channel 0 lower byte
DATA0HIGH Dh 7:0 ADC channel 0 upper byte
*/
/*
enum bcm2835I2CReasonCodes { BCM2835_I2C_REASON_OK = 0x00, BCM2835_I2C_REASON_ERROR_NACK = 0x01, BCM2835_I2C_REASON_ERROR_CLKT = 0x02, BCM2835_I2C_REASON_ERROR_DATA = 0x04 }
*/
if (!bcm2835_init())
return 1;
char uitgelezenTempWaarde[1];
int totalTemp[2];
int error =0;
bcm2835_i2c_begin(); // start i2c
bcm2835_i2c_setSlaveAddress(0x29); // slave address
bcm2835_i2c_set_baudrate(1000); // default
//----------- turn channels on for measurement ------
uitgelezenTempWaarde[0] = 0xa0;
error = bcm2835_i2c_write(uitgelezenTempWaarde,1);
if(error != 0x00)
{
printf("i2c error! : 0x%02X \n",error);
}
uitgelezenTempWaarde[0] = 0x03;
error = bcm2835_i2c_write(uitgelezenTempWaarde,1);
if(error != 0x00)
{
printf("i2c error! : 0x%02X \n",error);
}
bcm2835_delay(500);
error = bcm2835_i2c_read(uitgelezenTempWaarde,1);
if(error != 0x00)
{
printf("i2c error! : 0x%02X \n",error);
}
//----------- read data ------
uitgelezenTempWaarde[0] = 0xac; //DATA0LOW Ch 7:0 ADC channel 0 lower byte
error = bcm2835_i2c_write(uitgelezenTempWaarde,1);
if(error != 0x00)
{
printf("i2c error! : 0x%02X \n",error);
}
error = bcm2835_i2c_read(uitgelezenTempWaarde,1);
if(error != 0x00)
{
printf("i2c error! : 0x%02X \n",error);
}
totalTemp[1]= (int)uitgelezenTempWaarde[0];
uitgelezenTempWaarde[0] = 0xad; //DATA0HIGH Dh 7:0 ADC channel 0 upper byte
error = bcm2835_i2c_write(uitgelezenTempWaarde,1);
if(error != 0x00)
{
printf("i2c error! : 0x%02X \n",error);
}
error = bcm2835_i2c_read(uitgelezenTempWaarde,1);
if(error != 0x00)
{
printf("i2c error! : 0x%02X \n",error);
}
totalTemp[0] = (int)uitgelezenTempWaarde[0]; //
totalTemp[0] *= 256; //hex conversion for the highest byte so it is seen as a high number (16 bits)
printf("The light value is :%d\n",totalTemp[0]+totalTemp[1]);
bcm2835_i2c_end();
bcm2835_close();
return 0;
}

Blink keyboard LED one at a time driver in Linux

I tried to modify a driver to blink keyboard LED one at a time in Linux. However, what I get is all on
Here are codes. Any hints? The original one is to make all LEDS ON and blink it (i.e. use 0x07). What I did is to define a bunch of macros for each LED status.
struct timer_list my_timer;
struct tty_driver *my_driver;
char kbledstatus = 0;
#define BLINK_DELAY HZ/5
#define CAP 0x01
#define NUM 0x02
#define NUM_CAP 0x03
#define SCROLL 0x04
#define NUM_SCROLL 0x05
#define CAP_SCROLL 0x06
#define ALL_LEDS_ON 0x07
#define RESTORE_LEDS 0xFF
static void my_timer_func(unsigned long ptr)
{
int *pstatus = (int *)ptr;
if (*pstatus == ALL_LEDS_ON)
*pstatus = RESTORE_LEDS;
else
{
*pstatus = ALL_LEDS_ON;
*pstatus = CAP;
*pstatus =NUM;
*pstatus = NUM_CAP;
*pstatus = SCROLL;
*pstatus = NUM_SCROLL;
*pstatus = CAP_SCROLL;
}
(my_driver->ioctl) (vc_cons[fg_console].d->vc_tty, NULL, KDSETLED,
*pstatus);
my_timer.expires = jiffies + BLINK_DELAY;
add_timer(&my_timer);
}
/*
Keyboard LED Init Function
*/
static int __init kbleds_init(void)
{
int i;
printk(KERN_INFO "kbleds: loading\n");
printk(KERN_INFO "kbleds: fgconsole is %x\n", fg_console);
for (i = 0; i < MAX_NR_CONSOLES; i++)
{
if (!vc_cons[i].d)
break;
printk(KERN_INFO "console[%i/%i] #%i, tty %lx\n", i,
MAX_NR_CONSOLES, vc_cons[i].d->vc_num,
(unsigned long)vc_cons[i].d->vc_tty);
}
printk(KERN_INFO "kbleds: finished scanning consoles\n");
my_driver = vc_cons[fg_console].d->vc_tty->driver;
printk(KERN_INFO "kbleds: tty driver magic %x\n", my_driver->magic);
/*
* Set up the LED blink timer the first time
*/
init_timer(&my_timer);
my_timer.function = my_timer_func;
my_timer.data = (unsigned long)&kbledstatus;
my_timer.expires = jiffies + BLINK_DELAY;
add_timer(&my_timer);
return 0;
}

Resources