Skip to content
Browse files

Added support for I2C Oled

Rewrited I2C code of BCM2835
Added I2C Oled support
Speed coding, I need to cleanup the code later
  • Loading branch information...
1 parent 615cc26 commit 6e986fa7b08f0680d1be50584830bc152151280d @hallard committed Jun 30, 2013
Showing with 212 additions and 345 deletions.
  1. +146 −80 Adafruit_SSD1306.cpp
  2. +3 −0 Adafruit_SSD1306.h
  3. +1 −1 ArduiPi_SSD1306.h
  4. +58 −240 bcm2835.c
  5. +4 −24 bcm2835.h
View
226 Adafruit_SSD1306.cpp
@@ -181,7 +181,8 @@ boolean Adafruit_SSD1306::init(int8_t RST,int16_t SSD1306_LCDWIDTH, int16_t SSD1
return false;
// Init Raspberry PI I2C
- bcm2835_i2c_begin();
+ if (bcm2835_i2c_begin()==0)
+ return false;
return ( true);
}
@@ -228,9 +229,11 @@ void Adafruit_SSD1306::begin(uint8_t vccstate, uint8_t i2caddr) {
bcm2835_i2c_setSlaveAddress(i2caddr) ;
// Set clock to 400 KHz
- bcm2835_i2c_setClockDivider(BCM2835_I2C_CLOCK_DIVIDER_626);
+ // does not seem to work, will check this later
+ // bcm2835_i2c_set_baudrate(400000);
}
+
// Setup reset pin direction (used by both SPI and I2C)
bcm2835_gpio_fsel(rst, BCM2835_GPIO_FSEL_OUTP);
bcm2835_gpio_write(rst, HIGH);
@@ -246,43 +249,72 @@ void Adafruit_SSD1306::begin(uint8_t vccstate, uint8_t i2caddr) {
// bring out of reset
bcm2835_gpio_write(rst, HIGH);
-
- // turn on VCC (9V?)
-
-
- // Init sequence for OLED module
- ssd1306_command(SSD1306_DISPLAYOFF); // 0xAE
- ssd1306_command(SSD1306_SETDISPLAYCLOCKDIV); // 0xD5
- ssd1306_command(0x80); // the suggested ratio 0x80
- ssd1306_command(SSD1306_SETMULTIPLEX); // 0xA8
-
- ssd1306_command(ssd1306_lcdheight==32?0x1F:0x3F);
-
- ssd1306_command(SSD1306_SETDISPLAYOFFSET); // 0xD3
- ssd1306_command(0x0); // no offset
- ssd1306_command(SSD1306_SETSTARTLINE | 0x0); // line #0
- ssd1306_command(SSD1306_CHARGEPUMP); // 0x8D
- ssd1306_command(vccstate==SSD1306_EXTERNALVCC?0x10:0x14);
- ssd1306_command(SSD1306_MEMORYMODE); // 0x20
- ssd1306_command(0x00); // 0x0 act like ks0108
- ssd1306_command(SSD1306_SEGREMAP | 0x1);
- ssd1306_command(SSD1306_COMSCANDEC);
- ssd1306_command(SSD1306_SETCOMPINS); // 0xDA
- ssd1306_command(ssd1306_lcdheight==32?0x02:0x12);
- ssd1306_command(SSD1306_SETCONTRAST); // 0x81
-
- if (ssd1306_lcdheight == 32)
- ssd1306_command(0x8F);
+
+ // SPI oled does not seem to work with spi multiple byte command, I need to check that later
+ if (isSPI())
+ {
+ // Init sequence for OLED module
+ ssd1306_command(SSD1306_DISPLAYOFF); // 0xAE
+ ssd1306_command(SSD1306_SETDISPLAYCLOCKDIV); // 0xD5
+ ssd1306_command(0x80); // the suggested ratio 0x80
+ ssd1306_command(SSD1306_SETMULTIPLEX); // 0xA8
+
+ ssd1306_command(ssd1306_lcdheight==32?0x1F:0x3F);
+
+ ssd1306_command(SSD1306_SETDISPLAYOFFSET); // 0xD3
+ ssd1306_command(0x0); // no offset
+ ssd1306_command(SSD1306_SETSTARTLINE | 0x0); // line #0
+ ssd1306_command(SSD1306_CHARGEPUMP); // 0x8D
+ ssd1306_command(vccstate==SSD1306_EXTERNALVCC?0x10:0x14);
+ ssd1306_command(SSD1306_MEMORYMODE); // 0x20
+ ssd1306_command(0x00); // 0x0 act like ks0108
+ ssd1306_command(SSD1306_SEGREMAP | 0x1);
+ ssd1306_command(SSD1306_COMSCANDEC);
+ ssd1306_command(SSD1306_SETCOMPINS); // 0xDA
+ ssd1306_command(ssd1306_lcdheight==32?0x02:0x12);
+ ssd1306_command(SSD1306_SETCONTRAST); // 0x81
+
+ if (ssd1306_lcdheight == 32)
+ ssd1306_command(0x8F);
+ else
+ ssd1306_command(vccstate==SSD1306_EXTERNALVCC?0x9F:0xCF);
+
+ ssd1306_command(SSD1306_SETPRECHARGE); // 0xd9
+ ssd1306_command(vccstate==SSD1306_EXTERNALVCC?0x22:0xF1);
+ ssd1306_command(SSD1306_SETVCOMDETECT); // 0xDB
+ ssd1306_command(0x40);
+ ssd1306_command(SSD1306_DISPLAYALLON_RESUME); // 0xA4
+ ssd1306_command(SSD1306_NORMALDISPLAY); // 0xA6
+ ssd1306_command(SSD1306_DISPLAYON);
+ }
else
- ssd1306_command(vccstate==SSD1306_EXTERNALVCC?0x9F:0xCF);
-
- ssd1306_command(SSD1306_SETPRECHARGE); // 0xd9
- ssd1306_command(vccstate==SSD1306_EXTERNALVCC?0x22:0xF1);
- ssd1306_command(SSD1306_SETVCOMDETECT); // 0xDB
- ssd1306_command(0x40);
- ssd1306_command(SSD1306_DISPLAYALLON_RESUME); // 0xA4
- ssd1306_command(SSD1306_NORMALDISPLAY); // 0xA6
- ssd1306_command(SSD1306_DISPLAYON); //--turn on oled panel
+ {
+ ssd1306_command(SSD1306_DISPLAYOFF); // 0xAE
+ ssd1306_command(SSD1306_SETDISPLAYCLOCKDIV, 0x80); // 0xD5 + the suggested ratio 0x80
+ ssd1306_command(SSD1306_SETMULTIPLEX, ssd1306_lcdheight==32?0x1F:0x3F); // 0xA8 +
+ ssd1306_command(SSD1306_SETDISPLAYOFFSET, 0x00); // 0xD3 + no offset
+ ssd1306_command(SSD1306_SETSTARTLINE | 0x0); // line #0
+ ssd1306_command(SSD1306_CHARGEPUMP, vccstate==SSD1306_EXTERNALVCC?0x10:0x14); // 0x8D
+ ssd1306_command(SSD1306_MEMORYMODE, 0x00); // 0x20 0x0 act like ks0108
+ ssd1306_command(SSD1306_SEGREMAP | 0x1);
+ ssd1306_command(SSD1306_COMSCANDEC);
+ ssd1306_command(SSD1306_SETCOMPINS, ssd1306_lcdheight==32?0x02:0x12); // 0xDA
+
+ if (ssd1306_lcdheight == 32)
+ ssd1306_command(SSD1306_SETCONTRAST, 0x8F);
+ else
+ ssd1306_command(SSD1306_SETCONTRAST, vccstate==SSD1306_EXTERNALVCC?0x9F:0xCF);
+
+ ssd1306_command(SSD1306_SETPRECHARGE, vccstate==SSD1306_EXTERNALVCC?0x22:0xF1); // 0xd9
+ ssd1306_command(SSD1306_SETVCOMDETECT, 0x40); // 0xDB
+ ssd1306_command(SSD1306_DISPLAYALLON_RESUME); // 0xA4
+ ssd1306_command(SSD1306_NORMALDISPLAY); // 0xA6
+ ssd1306_command(0x21, 0x00, 0x7F); // Set column address; start 0, end 127
+ ssd1306_command(0x22, 0x00, 0x03); // Set row address; start 0, end 3
+ stopscroll();
+ ssd1306_command(SSD1306_DISPLAYON); //--turn on oled panel
+ }
+
}
@@ -309,14 +341,63 @@ void Adafruit_SSD1306::ssd1306_command(uint8_t c) {
{
// I2C
char buff[2] ;
- uint8_t control = 0x00; // Co = 0, D/C = 0
- buff[0] = control;
+ buff[0] = 0x00 ; // Co = 0, D/C = 0
buff[1] = c;
bcm2835_i2c_write(buff, sizeof(buff)) ;
}
}
+void Adafruit_SSD1306::ssd1306_command(uint8_t c0, uint8_t c1)
+{
+ char buff[3] ;
+ buff[1] = c0;
+ buff[2] = c1;
+
+ // Is SPI
+ if (isSPI())
+ {
+ // Setup D/C line to low
+ bcm2835_gpio_write(dc, LOW);
+
+ // Write Data
+ fastSPIwrite(&buff[1], 2);
+ }
+ else
+ {
+ // I2C
+ buff[0] = 0x00 ; // Co = 0, D/C = 0
+ bcm2835_i2c_write(buff, 3) ;
+ }
+}
+
+void Adafruit_SSD1306::ssd1306_command(uint8_t c0, uint8_t c1, uint8_t c2)
+{
+ char buff[4] ;
+
+ buff[1] = c0;
+ buff[2] = c1;
+ buff[3] = c2;
+
+ // Is SPI
+ if (isSPI())
+ {
+ // SPI
+ // Setup D/C line to low
+ bcm2835_gpio_write(dc, LOW);
+
+ // Write Data
+ fastSPIwrite(&buff[1], 3);
+ }
+ else
+ {
+ // I2C
+ buff[0] = 0x00; // Co = 0, D/C = 0;
+ bcm2835_i2c_write(buff, sizeof(buff)) ;
+ }
+}
+
+
// startscrollright
// Activate a right handed scroll for rows start through stop
// Hint, the display is 16 rows tall. To scroll the whole display, run:
@@ -409,18 +490,21 @@ void Adafruit_SSD1306::ssd1306_data(uint8_t c) {
}
}
-void Adafruit_SSD1306::display(void) {
- ssd1306_command(SSD1306_SETLOWCOLUMN | 0x0); // low col = 0
- ssd1306_command(SSD1306_SETHIGHCOLUMN | 0x0); // hi col = 0
- ssd1306_command(SSD1306_SETSTARTLINE | 0x0); // line #0
+void Adafruit_SSD1306::display(void)
+{
+ ssd1306_command(SSD1306_SETLOWCOLUMN | 0x0); // low col = 0
+ ssd1306_command(SSD1306_SETHIGHCOLUMN | 0x0); // hi col = 0
+ ssd1306_command(SSD1306_SETSTARTLINE | 0x0); // line #0
+
+ uint16_t i=0 ;
// SPI
if ( isSPI())
{
// set D/C line to High
bcm2835_gpio_write(dc, HIGH);
- for (uint16_t i=0; i<(ssd1306_lcdwidth*ssd1306_lcdheight/8); i++)
+ for ( i=0; i<(ssd1306_lcdwidth*ssd1306_lcdheight/8); i++)
{
fastSPIwrite(buffer[i]);
}
@@ -434,45 +518,23 @@ void Adafruit_SSD1306::display(void) {
}
}
}
+ // I2C
else
{
- char buff[1] ;
+ char buff[17] ;
+ uint8_t x ;
- // I2C
- for (uint16_t i=0; i<(ssd1306_lcdwidth*ssd1306_lcdheight/8); i++)
+ /// loop trought all buffer
+ for ( i=0; i<(ssd1306_lcdwidth*ssd1306_lcdheight/8); i++ )
{
- buff[0] = 0x40;
- bcm2835_i2c_write ( buff, sizeof(buff)) ;
-
- // send a bunch of data in one xmission
- // may be a bcm2835_i2c_write ( buffer, 16);
- // could work, I do not have LCD to test
- for (uint8_t x=0; x<16; x++)
- {
- //Wire.write(buffer[i]);
- buff[0] = buffer[i];
- bcm2835_i2c_write ( buff, sizeof(buff));
- i++;
- }
- i--;
- }
- // i wonder why we have to do this (check datasheet)
- if (ssd1306_lcdheight == 32)
- {
- for (uint16_t i=0; i<(ssd1306_lcdwidth*ssd1306_lcdheight/8); i++)
- {
- // send a bunch of data in one xmission
- buff[0] = 0x40;
- bcm2835_i2c_write ( buff, sizeof(buff)) ;
-
- buff[0] = 0x00;
- for (uint8_t x=0; x<16; x++)
- {
- bcm2835_i2c_write ( buff, sizeof(buff)) ;
- i++;
- }
- i--;
- }
+ buff[0] = 0x40; // Co = 0; D/C# = 1 for data
+
+ // send a bunch of 16 data byte in one xmission
+ for (x=0; x<16; x++)
+ buff[x+1] = buffer[i++];
+
+ bcm2835_i2c_write ( buff, sizeof(buff));
+ i--;
}
}
}
@@ -488,4 +550,8 @@ inline void Adafruit_SSD1306::fastSPIwrite(uint8_t d) {
bcm2835_spi_transfer(d);
}
+inline void Adafruit_SSD1306::fastSPIwrite(char* tbuf, uint32_t len) {
+
+ bcm2835_spi_writenb(tbuf, len);
+}
View
3 Adafruit_SSD1306.h
@@ -96,6 +96,8 @@ class Adafruit_SSD1306 : public Adafruit_GFX {
void begin(uint8_t switchvcc = SSD1306_SWITCHCAPVCC, uint8_t i2caddr = SSD1306_I2C_ADDRESS);
void ssd1306_command(uint8_t c);
+ void ssd1306_command(uint8_t c0, uint8_t c1);
+ void ssd1306_command(uint8_t c0, uint8_t c1, uint8_t c2);
void ssd1306_data(uint8_t c);
void clearDisplay(void);
@@ -118,6 +120,7 @@ class Adafruit_SSD1306 : public Adafruit_GFX {
int8_t _i2caddr, dc, rst, cs;
int16_t ssd1306_lcdwidth, ssd1306_lcdheight;
void fastSPIwrite(uint8_t c);
+ void fastSPIwrite(char* tbuf, uint32_t len);
void slowSPIwrite(uint8_t c);
volatile uint8_t *dcport;
View
2 ArduiPi_SSD1306.h
@@ -28,7 +28,7 @@
#define OLED_SPI_CS0 BCM2835_SPI_CS0 /* Chip Select CE0 */
#define OLED_SPI_CS1 BCM2835_SPI_CS1 /* Chip Select CE1 */
#define OLED_SPI_CS BCM2835_SPI_CS1 /* Default Chip Select */
-#define OLED_I2C_RESET 4
+#define OLED_I2C_RESET RPI_V2_GPIO_P1_22 /* GPIO 25 pin 12 */
// Arduino Compatible type
typedef uint8_t boolean;
View
298 bcm2835.c
@@ -18,16 +18,18 @@
// 06/29/2013 Incorporated latest version of bcm2825.h done by Mike McCauley
-#include <stdlib.h>
#include <stdio.h>
-#include <errno.h>
+#include <stdlib.h>
#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <linux/i2c-dev.h>
+
+#include <errno.h>
#include <sys/mman.h>
#include <string.h>
#include <sys/time.h>
#include <time.h>
#include <unistd.h>
-
#include "bcm2835.h"
// This define enables a little test program (by default a blinking output on pin RPI_GPIO_PIN_11)
@@ -55,6 +57,9 @@ static uint8_t debug = 0;
// I2C The time needed to transmit one byte. In microseconds.
static int i2c_byte_wait_us = 0;
+// i2c file descriptor for opeping i2c device
+static int i2c_fd = 0;
+
// SPI Custom Chip Select Pin
static int spi_custom_cs = 0;
@@ -803,270 +808,83 @@ void bcm2835_spi_setChipSelectPolarity(uint8_t cs, uint8_t active)
}
}
-void bcm2835_i2c_begin(void)
+int bcm2835_i2c_begin(void)
{
- volatile uint32_t* paddr = bcm2835_bsc1 + BCM2835_BSC_DIV/4;
-
- // Set the I2C/BSC1 pins to the Alt 0 function to enable I2C access on them
- bcm2835_gpio_fsel(RPI_V2_GPIO_P1_03, BCM2835_GPIO_FSEL_ALT0); // SDA
- bcm2835_gpio_fsel(RPI_V2_GPIO_P1_05, BCM2835_GPIO_FSEL_ALT0); // SCL
-
- // Read the clock divider register
- uint16_t cdiv = bcm2835_peri_read(paddr);
- // Calculate time for transmitting one byte
- // 1000000 = micros seconds in a second
- // 9 = Clocks per byte : 8 bits + ACK
- i2c_byte_wait_us = ((float)cdiv / BCM2835_CORE_CLK_HZ) * 1000000 * 9;
-}
+ int fd ;
-void bcm2835_i2c_end(void)
-{
- // Set all the I2C/BSC1 pins back to input
- bcm2835_gpio_fsel(RPI_V2_GPIO_P1_03, BCM2835_GPIO_FSEL_INPT); // SDA
- bcm2835_gpio_fsel(RPI_V2_GPIO_P1_05, BCM2835_GPIO_FSEL_INPT); // SCL
+ if ((fd = open (bcm2835_get_pi_version() == 1 ? "/dev/i2c-0":"/dev/i2c-1" , O_RDWR)) < 0)
+ return fd;
+
+ // Set i2c descriptor
+ i2c_fd = fd;
+
+ return i2c_fd ;
+
}
-void bcm2835_i2c_setSlaveAddress(uint8_t addr)
+void bcm2835_i2c_end(void)
{
- // Set I2C Device Address
- volatile uint32_t* paddr = bcm2835_bsc1 + BCM2835_BSC_A/4;
- bcm2835_peri_write(paddr, addr);
+ // close i2c bus
+ if ( i2c_fd )
+ {
+ close(i2c_fd);
+ i2c_fd = 0;
+ }
}
-// defaults to 0x5dc, should result in a 166.666 kHz I2C clock frequency.
-// The divisor must be a power of 2. Odd numbers
-// rounded down.
-void bcm2835_i2c_setClockDivider(uint16_t divider)
+int bcm2835_i2c_setSlaveAddress(uint8_t addr)
{
- volatile uint32_t* paddr = bcm2835_bsc1 + BCM2835_BSC_DIV/4;
- bcm2835_peri_write(paddr, divider);
- // Calculate time for transmitting one byte
- // 1000000 = micros seconds in a second
- // 9 = Clocks per byte : 8 bits + ACK
- i2c_byte_wait_us = ((float)divider / BCM2835_CORE_CLK_HZ) * 1000000 * 9;
-}
+ if (!i2c_fd)
+ return (-1);
+ // Set I2C Device Address
+ return (ioctl (i2c_fd, I2C_SLAVE, addr) );
+
+}
// set I2C clock divider by means of a baudrate number
void bcm2835_i2c_set_baudrate(uint32_t baudrate)
{
+ volatile uint32_t* paddr = bcm2835_bsc1 + BCM2835_BSC_DIV/4;
+
uint32_t divider;
+
// use 0xFFFE mask to limit a max value and round down any odd number
divider = (BCM2835_CORE_CLK_HZ / baudrate) & 0xFFFE;
- bcm2835_i2c_setClockDivider( (uint16_t)divider );
+
+ bcm2835_peri_write(paddr, divider);
}
// Writes an number of bytes to I2C
-uint8_t bcm2835_i2c_write(const char * buf, uint32_t len)
+int bcm2835_i2c_write(const char * buf, uint32_t len)
{
- volatile uint32_t* dlen = bcm2835_bsc1 + BCM2835_BSC_DLEN/4;
- volatile uint32_t* fifo = bcm2835_bsc1 + BCM2835_BSC_FIFO/4;
- volatile uint32_t* status = bcm2835_bsc1 + BCM2835_BSC_S/4;
- volatile uint32_t* control = bcm2835_bsc1 + BCM2835_BSC_C/4;
-
- uint32_t remaining = len;
- uint32_t i = 0;
- uint8_t reason = BCM2835_I2C_REASON_OK;
-
- // Clear FIFO
- bcm2835_peri_set_bits(control, BCM2835_BSC_C_CLEAR_1 , BCM2835_BSC_C_CLEAR_1 );
- // Clear Status
- bcm2835_peri_write_nb(status, BCM2835_BSC_S_CLKT | BCM2835_BSC_S_ERR | BCM2835_BSC_S_DONE);
- // Set Data Length
- bcm2835_peri_write_nb(dlen, len);
-
- // pre populate FIFO with max buffer
- while( remaining && ( i < BCM2835_BSC_FIFO_SIZE ) )
- {
- bcm2835_peri_write_nb(fifo, buf[i]);
- i++;
- remaining--;
- }
-
- // Enable device and start transfer
- bcm2835_peri_write_nb(control, BCM2835_BSC_C_I2CEN | BCM2835_BSC_C_ST);
-
- // Transfer is over when BCM2835_BSC_S_DONE
- while(!(bcm2835_peri_read_nb(status) & BCM2835_BSC_S_DONE ))
- {
- while ( remaining && (bcm2835_peri_read_nb(status) & BCM2835_BSC_S_TXD ))
- {
- // Write to FIFO, no barrier
- bcm2835_peri_write_nb(fifo, buf[i]);
- i++;
- remaining--;
- }
- }
-
- // Received a NACK
- if (bcm2835_peri_read(status) & BCM2835_BSC_S_ERR)
- {
- reason = BCM2835_I2C_REASON_ERROR_NACK;
- }
-
- // Received Clock Stretch Timeout
- else if (bcm2835_peri_read(status) & BCM2835_BSC_S_CLKT)
- {
- reason = BCM2835_I2C_REASON_ERROR_CLKT;
- }
-
- // Not all data is sent
- else if (remaining)
- {
- reason = BCM2835_I2C_REASON_ERROR_DATA;
- }
+ int reason = -1 ;
+
+ if (!i2c_fd)
+ return (-1);
+
+ // Do simple use of I2C smbus command regarding number of bytes to transfer
+ // Write 1 byte
+ if (len == 2)
+ reason = i2c_smbus_write_byte_data(i2c_fd, buf[0], buf[1]);
+ // Write 1 word
+ else if (len == 3)
+ reason = i2c_smbus_write_word_data(i2c_fd, buf[0], (buf[2]<<8) | buf[1] );
+ // Write bulk data
+ else
+ reason = i2c_smbus_write_i2c_block_data(i2c_fd, buf[0], len-1, (const __u8 *) &buf[1]);
+
+ usleep(1);
- bcm2835_peri_set_bits(control, BCM2835_BSC_S_DONE , BCM2835_BSC_S_DONE);
+ return ( reason );
- return reason;
}
// Read an number of bytes from I2C
+// to do
uint8_t bcm2835_i2c_read(char* buf, uint32_t len)
{
- volatile uint32_t* dlen = bcm2835_bsc1 + BCM2835_BSC_DLEN/4;
- volatile uint32_t* fifo = bcm2835_bsc1 + BCM2835_BSC_FIFO/4;
- volatile uint32_t* status = bcm2835_bsc1 + BCM2835_BSC_S/4;
- volatile uint32_t* control = bcm2835_bsc1 + BCM2835_BSC_C/4;
-
- uint32_t remaining = len;
- uint32_t i = 0;
- uint8_t reason = BCM2835_I2C_REASON_OK;
-
- // Clear FIFO
- bcm2835_peri_set_bits(control, BCM2835_BSC_C_CLEAR_1 , BCM2835_BSC_C_CLEAR_1 );
- // Clear Status
- bcm2835_peri_write_nb(status, BCM2835_BSC_S_CLKT | BCM2835_BSC_S_ERR | BCM2835_BSC_S_DONE);
- // Set Data Length
- bcm2835_peri_write_nb(dlen, len);
- // Start read
- bcm2835_peri_write_nb(control, BCM2835_BSC_C_I2CEN | BCM2835_BSC_C_ST | BCM2835_BSC_C_READ);
-
- // wait for transfer to complete
- while (!(bcm2835_peri_read_nb(status) & BCM2835_BSC_S_DONE))
- {
- // we must empty the FIFO as it is populated and not use any delay
- while (bcm2835_peri_read_nb(status) & BCM2835_BSC_S_RXD)
- {
- // Read from FIFO, no barrier
- buf[i] = bcm2835_peri_read_nb(fifo);
- i++;
- remaining--;
- }
- }
-
- // transfer has finished - grab any remaining stuff in FIFO
- while (remaining && (bcm2835_peri_read_nb(status) & BCM2835_BSC_S_RXD))
- {
- // Read from FIFO, no barrier
- buf[i] = bcm2835_peri_read_nb(fifo);
- i++;
- remaining--;
- }
-
- // Received a NACK
- if (bcm2835_peri_read(status) & BCM2835_BSC_S_ERR)
- {
- reason = BCM2835_I2C_REASON_ERROR_NACK;
- }
-
- // Received Clock Stretch Timeout
- else if (bcm2835_peri_read(status) & BCM2835_BSC_S_CLKT)
- {
- reason = BCM2835_I2C_REASON_ERROR_CLKT;
- }
-
- // Not all data is received
- else if (remaining)
- {
- reason = BCM2835_I2C_REASON_ERROR_DATA;
- }
-
- bcm2835_peri_set_bits(control, BCM2835_BSC_S_DONE , BCM2835_BSC_S_DONE);
-
- return reason;
-}
-
-// Read an number of bytes from I2C sending a repeated start after writing
-// the required register. Only works if your device supports this mode
-uint8_t bcm2835_i2c_read_register_rs(char* regaddr, char* buf, uint32_t len)
-{
- volatile uint32_t* dlen = bcm2835_bsc1 + BCM2835_BSC_DLEN/4;
- volatile uint32_t* fifo = bcm2835_bsc1 + BCM2835_BSC_FIFO/4;
- volatile uint32_t* status = bcm2835_bsc1 + BCM2835_BSC_S/4;
- volatile uint32_t* control = bcm2835_bsc1 + BCM2835_BSC_C/4;
-
- uint32_t remaining = len;
- uint32_t i = 0;
- uint8_t reason = BCM2835_I2C_REASON_OK;
-
- // Clear FIFO
- bcm2835_peri_set_bits(control, BCM2835_BSC_C_CLEAR_1 , BCM2835_BSC_C_CLEAR_1 );
- // Clear Status
- bcm2835_peri_write_nb(status, BCM2835_BSC_S_CLKT | BCM2835_BSC_S_ERR | BCM2835_BSC_S_DONE);
- // Set Data Length
- bcm2835_peri_write_nb(dlen, 1);
- // Enable device and start transfer
- bcm2835_peri_write_nb(control, BCM2835_BSC_C_I2CEN);
- bcm2835_peri_write_nb(fifo, regaddr[0]);
- bcm2835_peri_write_nb(control, BCM2835_BSC_C_I2CEN | BCM2835_BSC_C_ST);
-
- // poll for transfer has started
- while ( !( bcm2835_peri_read_nb(status) & BCM2835_BSC_S_TA ) )
- {
- // Linux may cause us to miss entire transfer stage
- if(bcm2835_peri_read(status) & BCM2835_BSC_S_DONE)
- break;
- }
-
- // Send a repeated start with read bit set in address
- bcm2835_peri_write_nb(dlen, len);
- bcm2835_peri_write_nb(control, BCM2835_BSC_C_I2CEN | BCM2835_BSC_C_ST | BCM2835_BSC_C_READ );
-
- // Wait for write to complete and first byte back.
- bcm2835_delayMicroseconds(i2c_byte_wait_us * 3);
-
- // wait for transfer to complete
- while (!(bcm2835_peri_read_nb(status) & BCM2835_BSC_S_DONE))
- {
- // we must empty the FIFO as it is populated and not use any delay
- while (remaining && bcm2835_peri_read_nb(status) & BCM2835_BSC_S_RXD)
- {
- // Read from FIFO, no barrier
- buf[i] = bcm2835_peri_read_nb(fifo);
- i++;
- remaining--;
- }
- }
-
- // transfer has finished - grab any remaining stuff in FIFO
- while (remaining && (bcm2835_peri_read_nb(status) & BCM2835_BSC_S_RXD))
- {
- // Read from FIFO, no barrier
- buf[i] = bcm2835_peri_read_nb(fifo);
- i++;
- remaining--;
- }
-
- // Received a NACK
- if (bcm2835_peri_read(status) & BCM2835_BSC_S_ERR)
- {
- reason = BCM2835_I2C_REASON_ERROR_NACK;
- }
-
- // Received Clock Stretch Timeout
- else if (bcm2835_peri_read(status) & BCM2835_BSC_S_CLKT)
- {
- reason = BCM2835_I2C_REASON_ERROR_CLKT;
- }
-
- // Not all data is sent
- else if (remaining)
- {
- reason = BCM2835_I2C_REASON_ERROR_DATA;
- }
-
- bcm2835_peri_set_bits(control, BCM2835_BSC_S_DONE , BCM2835_BSC_S_DONE);
+ uint8_t reason = 0;
return reason;
}
View
28 bcm2835.h
@@ -1107,7 +1107,7 @@ extern "C" {
/// You should call bcm2835_i2c_end() when all I2C functions are complete to return the pins to
/// their default functions
/// \sa bcm2835_i2c_end()
- extern void bcm2835_i2c_begin(void);
+ extern int bcm2835_i2c_begin(void);
/// End I2C operations.
/// I2C pins P1-03 (SDA) and P1-05 (SCL)
@@ -1116,13 +1116,8 @@ extern "C" {
/// Sets the I2C slave address.
/// \param[in] addr The I2C slave address.
- extern void bcm2835_i2c_setSlaveAddress(uint8_t addr);
+ extern int bcm2835_i2c_setSlaveAddress(uint8_t addr);
- /// Sets the I2C clock divider and therefore the I2C clock speed.
- /// \param[in] divider The desired I2C clock divider, one of BCM2835_I2C_CLOCK_DIVIDER_*,
- /// see \ref bcm2835I2CClockDivider
- extern void bcm2835_i2c_setClockDivider(uint16_t divider);
-
/// Sets the I2C clock divider by converting the baudrate parameter to
/// the equivalent I2C clock divider. ( see \sa bcm2835_i2c_setClockDivider)
/// For the I2C standard 100khz you would set baudrate to 100000
@@ -1134,8 +1129,8 @@ extern "C" {
/// (as previously set by \sa bcm2835_i2c_setSlaveAddress)
/// \param[in] buf Buffer of bytes to send.
/// \param[in] len Number of bytes in the buf buffer, and the number of bytes to send.
- /// \return reason see \ref bcm2835I2CReasonCodes
- extern uint8_t bcm2835_i2c_write(const char * buf, uint32_t len);
+ /// \return i2c smbus command return code
+ extern int bcm2835_i2c_write(const char * buf, uint32_t len);
/// Transfers any number of bytes from the currently selected I2C slave.
/// (as previously set by \sa bcm2835_i2c_setSlaveAddress)
@@ -1144,21 +1139,6 @@ extern "C" {
/// \return reason see \ref bcm2835I2CReasonCodes
extern uint8_t bcm2835_i2c_read(char* buf, uint32_t len);
- /// Allows reading from I2C slaves that require a repeated start (without any prior stop)
- /// to read after the required slave register has been set. For example, the popular
- /// MPL3115A2 pressure and temperature sensor. Note that your device must support or
- /// require this mode. If your device does not require this mode then the standard
- /// combined:
- /// \sa bcm2835_i2c_write
- /// \sa bcm2835_i2c_read
- /// are a better choice.
- /// Will read from the slave previously set by \sa bcm2835_i2c_setSlaveAddress
- /// \param[in] regaddr Buffer containing the slave register you wish to read from.
- /// \param[in] buf Buffer of bytes to receive.
- /// \param[in] len Number of bytes in the buf buffer, and the number of bytes to received.
- /// \return reason see \ref bcm2835I2CReasonCodes
- extern uint8_t bcm2835_i2c_read_register_rs(char* regaddr, char* buf, uint32_t len);
-
/// @}
/// \defgroup st System Timer access

0 comments on commit 6e986fa

Please sign in to comment.
Something went wrong with that request. Please try again.