RedBearLab / nRF51822-Arduino

Moved to https://github.com/redbear/nRF5x
252 stars 109 forks source link

Serious issues with i2c sensor.. #38

Open Tealons opened 8 years ago

Tealons commented 8 years ago

Hi,

I'm trying to get an i2c sensor (the BMP180 from Sparkfun) up and running for the past few days with the arduino environment. However, without any luck. On an arduino I get it up and running in 5 minutes, but with the nano it has been nothing but trouble the past couple of days.

The first feeling I got that something might be wrong is the fact that the compiler gives the error that SCL1 and SDA1 are not defined. Seems like the wire.h implementation is messy and not well tested. Searching on your support forum gave no real help. All the answers there are short and not really helpfull. Scanning with an i2c scanner always give the same result... Device not found.

Please provide a working implementation of wire.h so I can hook up my i2c sensor. From the other issues that are posted the past couple of days, it seems that you have some serious issues with the arduino implementation..

Cheong2K commented 8 years ago

Hi, please show your code here for evaluation.

Cheong2K commented 8 years ago

Hi, I have assigned an engineer looking at this, will get back to you as soon as possible.

Tealons commented 8 years ago
#include <Wire.h>

#define TXRX_BUF_LEN 20
BLE ble;

static boolean analog_enabled = false;
static byte old_state         = LOW;

// The Nordic UART Service
static const uint8_t service1_uuid[]                = {0x71, 0x3D, 0, 0, 0x50, 0x3E, 0x4C, 0x75, 0xBA, 0x94, 0x31, 0x48, 0xF1, 0x8D, 0x94, 0x1E};
static const uint8_t service1_tx_uuid[]             = {0x71, 0x3D, 0, 3, 0x50, 0x3E, 0x4C, 0x75, 0xBA, 0x94, 0x31, 0x48, 0xF1, 0x8D, 0x94, 0x1E};
static const uint8_t service1_rx_uuid[]             = {0x71, 0x3D, 0, 2, 0x50, 0x3E, 0x4C, 0x75, 0xBA, 0x94, 0x31, 0x48, 0xF1, 0x8D, 0x94, 0x1E};
static const uint8_t uart_base_uuid_rev[]           = {0x1E, 0x94, 0x8D, 0xF1, 0x48, 0x31, 0x94, 0xBA, 0x75, 0x4C, 0x3E, 0x50, 0, 0, 0x3D, 0x71};

uint8_t tx_value[TXRX_BUF_LEN] = {0,};
uint8_t rx_value[TXRX_BUF_LEN] = {0,};

GattCharacteristic  characteristic1(service1_tx_uuid, tx_value, 1, TXRX_BUF_LEN, GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE_WITHOUT_RESPONSE );

GattCharacteristic  characteristic2(service1_rx_uuid, rx_value, 1, TXRX_BUF_LEN, GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY);

GattCharacteristic *uartChars[] = {&characteristic1, &characteristic2};

GattService         uartService(service1_uuid, uartChars, sizeof(uartChars) / sizeof(GattCharacteristic *));

static void disconnectionCallBack(Gap::Handle_t handle, Gap::DisconnectionReason_t reason)
{
    Serial1.println("Disconnected!");
    Serial1.println("Restarting the advertising process");
    ble.startAdvertising();
}

void setup() {
    // put your setup code here, to run once

    Serial1.begin(9600);
    ble.init();
    ble.onDisconnection(disconnectionCallBack);

    // setup adv_data and srp_data
    ble.accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED);
    ble.accumulateAdvertisingPayload(GapAdvertisingData::SHORTENED_LOCAL_NAME,
                                     (const uint8_t *)"BLAAT", sizeof("BLAAT") - 1);
    ble.accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_128BIT_SERVICE_IDS,
                                     (const uint8_t *)uart_base_uuid_rev, sizeof(uart_base_uuid_rev));

    // set adv_type
    ble.setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);    
      // add service
    ble.addService(uartService);
    // set device name
    ble.setDeviceName((const uint8_t *)"Simple Controls");
    // set tx power,valid values are -40, -20, -16, -12, -8, -4, 0, 4
    ble.setTxPower(4);
    // set adv_interval, 100ms in multiples of 0.625ms.
    ble.setAdvertisingInterval(160);
    // set adv_timeout, in seconds
    ble.setAdvertisingTimeout(0);
    // start advertising
    ble.startAdvertising();
    Serial1.println("Advertising Start!");

    Wire.begin();
    Serial1.println("Wire.begin called");
}

void loop() {
    ble.waitForEvent();

    byte error, address;
    int nDevices;

    Serial1.println("Scanning for i2c device...");

    nDevices = 0;
    for(address = 1; address < 127; address++ )
    {
      // The i2c_scanner uses the return value of
      // the Write.endTransmisstion to see if
      // a device did acknowledge to the address.
      Wire.beginTransmission(address);
      error = Wire.endTransmission();

    if (error == 0)
    {
      uint8_t buf[3];

      //send string to mobile and serial port to indicate that device is found.
      Serial1.print("I2C device found at address 0x");
       if (address<16)
        Serial1.print("0");
      Serial1.print(address,HEX);
      Serial1.println("  !");

      buf[0] = (0x74);
      buf[1] = (0x65);
      buf[2] = (0x73);
      buf[3] = (0x74); 
      ble.updateCharacteristicValue(characteristic2.getValueAttribute().getHandle(), buf, 4);

      nDevices++;
    } else if (error==4){

      //send string to mobile and serial port to indicate that device?? (or error) is found. 
      Serial1.print("Unknow error at address 0x");
      if (address<16)
        Serial1.print("0");
      Serial1.println(address,HEX);

      uint8_t buf[3];
      buf[0] = (0x74);
      buf[1] = (0x65);
      buf[2] = (0x73);
      buf[3] = (0x74);  
      ble.updateCharacteristicValue(characteristic2.getValueAttribute().getHandle(), buf, 4);
    }    
  }
  if (nDevices == 0){
    Serial1.println("No I2C devices found\n");
    uint8_t buf[3];
    buf[0] = (0x6e);
    buf[1] = (0x6f);
    buf[2] = (0x74);

    ble.updateCharacteristicValue(characteristic2.getValueAttribute().getHandle(), buf, 3);

  }else{
    uint8_t buf[3];
    buf[0] = (0x74);
    buf[1] = (0x6f);
    buf[2] = (0x6e);

    ble.updateCharacteristicValue(characteristic2.getValueAttribute().getHandle(), buf, 3);
    Serial1.println("done\n");
  }
  delay(1000);           // wait a second for next scan
}

The same code, with the ble specific parts commented out, is used on an Arduino Deumilanove. Works without a problem. To confirm the correct functioning of the Nano, I created a cordova app. The 'not' string is send, so the scanning code is executed.

On the Arduino I also have to replace the Serial1 with Serial.

Cheong2K commented 8 years ago

Hi, thank you for pointing out this.

There is a fix to the I2C, changes SCL1 -> I2C_SCL0 and SDA1 -> I2C_SDA0 https://github.com/RedBearLab/nRF51822-Arduino/blob/S130/arduino-1.6.x/hardware/RBL/RBL_nRF51822/libraries/Wire/Wire.cpp

Would you mind to help testing it with your sensor?

We will release it with the board package to the Boards Manager soon.

Tealons commented 8 years ago

It fixed the build error, but still no sensor detected. I'm on holiday at home, so plenty of time to help you fix this by Skype or something else...

Cheong2K commented 8 years ago

which two pins do you use for the I2C ?

Tealons commented 8 years ago

I have attached photo's of my setup. While I was making the photo's I wondered if I need to apply pull-up resistors? I don't need them on my Arduino, but maybe the Nano needs them? img_20151202_100323 img_20151202_100348 img_20151202_100356

Cheong2K commented 8 years ago

In your photos, it looks correct (D2 and D3 for the I2C) Yes, you need pull up resistors for the I2C pins unless your sensor board has.

Tealons commented 8 years ago

My Bad. The board has them: http://cdn.sparkfun.com/datasheets/Sensors/Pressure/BMP180%20breakout.pdf

I don't have a scope to check the signals... So what are the next steps to tackle this issue?

Cheong2K commented 8 years ago

please hold on, my engineer is looking into this.

Tealons commented 8 years ago

@Cheong2K Any news? Or an ETA when your engineer will have the library fixed?

Cheong2K commented 8 years ago

Hi, he should have fixed, please check.

Tealons commented 8 years ago

No change. Still not working. Please advise on the next steps...

Tealons commented 8 years ago

Interestingly the pin numbers used by the wire.begin() function changed from 10 & 8 to 3 & 2 ??!! What's going on??

zoujixing commented 8 years ago

See RBL_nRF51822\variants\BLE_Nano\pins_arduino.h, TWI_SDA is D2 and TWI_SCL is D3.Throught function "Pin_nRF51822_to_Arduino",We get the P0.10 and P0.08. I test it with example "AT24C512_Demo", it work ok.

Tealons commented 8 years ago

@zoujixing Yeah, I saw that too. I was more concerned with the commit earlier to fix the build error? Also, was the example not supposed to work from the beginning? I'm a little sceptical that it works now. Did you look at my code? Could you get it to work?

Tealons commented 8 years ago

Same script, without the BLE stuff, with an Arduino Duemilanove setup in 2 minutes:

test serial export

This should be just as easy with the Nano.... But now 5 days and counting to get this work.

Cheong2K commented 8 years ago

Sorry for that, we have try our best.

Cheong2K commented 8 years ago

It is too difficult to be 100% compatible for the BLE Nano (ARM) with the Atmel chips (AVR 8-bit) using your code posted. The lower layer driver from Nordic has its limitation.

zoujixing commented 8 years ago

@Tealons I have modified I2C library, try it by follow code :
for(index1=0; index1<127; index1++) { Wire.beginTransmission(index1); err_code = Wire.endTransmission(); Serial1.print("The addr1 : "); Serial1.println(index1, HEX); if(err_code == -1) Serial1.println("No slave device"); else if(err_code == -2) Serial1.println("i2c bus busy"); else if(err_code == 0) Serial1.println("i2c slave device exist"); Serial1.print("\r\n \r\n"); delay(500); }

Tealons commented 8 years ago

I will try the new code out tomorrow. I'm at a conference today. @Cheong2K Does it help if I switch to the mbed or Nordic environments instead of that of the Arduino?

Cheong2K commented 8 years ago

I think so, they have a lot of engineers to support you.

Tealons commented 8 years ago

Which one is the better pick in terms of support, examples and standard libraries?

Cheong2K commented 8 years ago

If you are good at MCU development and you know how to setup the development environment, you should use Nordic SDK directly, this allows you to use latest development tools of Nordic. The problem is you have to use the low level API yourself. You need to pay for the compiler if you are going to use the Keil IDE.

mbed is an online development platform and you don't need to pay for the compiler, you don't need to setup any development environment and it has a lot of examples/libraries for you to use.

In terms of support, I can't say how good they can help but you can make use of their forum and you can also submit a case in Nordic's portal, they will provide support to you.

Tealons commented 8 years ago

I now get a device on every address....

1vav commented 8 years ago

Any updates on this one? I find a similar issue with both a PN532 breakout, and a BNO055 breakout. NO_SLAVE. I tried to use several different pins, and update locations in pins_arduino.h to the correct values, as well as use the Wire.begin(SCL, SDA, TWI_SPEED) function to ensure correct pins. I've also connected two 4.7k pullups just in case. No luck :( I have the latest copy of the library with all the latest edits to overcome earlier issues such as address >> 1. Any help would be appreciated. How does the solution work for one board (the eeprom) but not another (PN532, a very common arduino breakout)?

1vav commented 8 years ago

There seems to be other mbed code out there which also has a TWI interface. Any learning from that code that can be applied to this?

https://github.com/Seeed-Studio/mbed_ble

1vav commented 8 years ago

SOLVED!

Scanning... I2C device found at address 0x24 ! I2C device found at address 0x28 ! 2I2C devices found

This is the things I had to change:

  1. output drive - by default, mbed has set the i2c Output Drive to 0.5mA - not enough to pull down external pullups below 10k. Especially if there are more than one breakout boards in parallel, good luck! Fortunately, nRF drives 10x that by changing this setting in i2c_api.c in TWO PLACES: OLD: (GPIO_PIN_CNF_DRIVE_**S**0D1 << GPIO_PIN_CNF_DRIVE_Pos) | NEW: (GPIO_PIN_CNF_DRIVE_**H**0D1 << GPIO_PIN_CNF_DRIVE_Pos) |
  2. pin mapping - the pin mapping in RBL BLENano is messedup. What shows as P06 and P07 externally is actually pins '14' and '7', in file 'pin_transform.cpp'
#ifdef BLE_NANO
    switch(pin)
    {   
        case 0 : return_pin = P0_11;break;      //D0/RXD/MISO
        case 1 : return_pin = P0_9;break;       //D1/TXD/MOSI
        case 2 : return_pin = P0_10;break;      //D2/CTS/CS/SDA
        case 3 : return_pin = P0_8;break;       //D3/RTS/SCK/SCL

        case 4 : return_pin = P0_28;break;      //D4
        case 5 : return_pin = P0_29;break;      //D5
        case 6 : return_pin = P0_15;break;      //D6
        case 7 : return_pin = P0_7;break;       //D7

        case 13 : return_pin = P0_19;break;     //D13/LED

        case 8 : return_pin = P0_1;break;       //A0
        case 9 : return_pin = P0_2;break;       //A1
        case 10 : return_pin = P0_3;break;      //A2
        case 11 : return_pin = P0_4;break;      //A3
        case 12 : return_pin = P0_5;break;      //A4
        case 14 : return_pin = P0_6;break;      //A5

        default : return_pin = (PinName)NC;break;       
    }
#endif

My SCL was connected to the conveniently available pad on the BLE Nano, P06, marked as '14' here. And the SDA was next to it, P07, marked as '7' So I had to call the I2C initialization as: Wire.begin(**14, 7,** TWI_FREQUENCY_100K);

Tealons commented 8 years ago

@1vav I never found the time to digg deeper into the issue. So I'm glad you fixed it! I will try it out right away!

1vav commented 8 years ago

@Tealons , hope this works for you, just make sure to initialize your I2C with your particular pins. That file I posted above might have a different version for your download, so make sure to find the right pin transform file. Second, TWI libraries initialize Wire.begin() without SCL SDA overriding function. So make sure in every file in the hierarchy, the SCL and SDA are defined to your liking, or that at every hierarchy the Wire.begin(SCL,SDA,I2CSPEED) calls are used. It's classic bad coding issues seen at play here, hard-coding (SCL SDA and pin transform values), multiple code fragments doing the same thing (begin calls), and bad documentation (or lack thereof)

liliumjsn commented 8 years ago

Hello 1vav, I have RBL nRF51822 board and i think i have the same issue with you but i cannot fix it. I'm using the latest Wire.h and Wire.cpp from here (https://developer.mbed.org/teams/RedBearLab/code/I2C_Demo/) and tried GPIO_PIN_CNFDRIVEH0D1 change, but no luck. I have 3 I2C devices connected on pins p5(SCL) and p4(SDA), and when i run the i2c scanner example i get "No I2C devices found". If you have any idea about this please help. Thank you.

1vav commented 8 years ago

Check all I2C chips/board schematics- SDA and SCL pins have pullup resistors. If all the pullups on a line are less than 4.7k together, it's possible the bus will fail. If so, remove the resistors such that the value goes up to 10k or so. That's just one possibility. Also, test the i2c devices one by one. I2c scanner is a great program for this. Also make sure the TWI is getting correctly initialized - often begin() functions cause the bus to default to some pins which may not be the correct ones. Use begin(scl, sda, twi_frequency) versions of the functions with the sda and scl pins correctly representing your wiring. Also note that pin '5' on code might map to a totally different port number on the nrf, like 0.12 or such. On Apr 7, 2016 4:25 PM, "Lilium JSN" notifications@github.com wrote:

Hello 1vav, I have RBL nRF51822 board and i think i have the same issue with you but i cannot fix it. I'm using the latest Wire.h and Wire.cpp from here ( https://developer.mbed.org/teams/RedBearLab/code/I2C_Demo/) and tried GPIO_PIN_CNF_DRIVE__H_0D1 change, but no luck. I have 3 I2C devices connected on pins p5(SCL) and p4(SDA), and when i run the i2c scanner example i get "No I2C devices found". If you have any idea about this please help. Thank you.

— You are receiving this because you were mentioned. Reply to this email directly or view it on GitHub https://github.com/RedBearLab/nRF51822-Arduino/issues/38#issuecomment-207135862

liliumjsn commented 8 years ago

Thanks for your answer. To start with, can you please verify what Wire files' version did you use? It seems that this one for example (https://developer.mbed.org/teams/RedBearLab/code/I2C_Demo/file/0298ffee8eba/wire.cpp) is not using pin_transform. Total resistor pullup value is 10K and i've checked the schematics a hundred times today. arduinoPin23 should be SCL/nrfP0_5 and arduinoPin22 should be SDA/nrfP0_4. Here is my code: .ino

// --------------------------------------
// i2c_scanner
//
// Version 1
//    This program (or code that looks like it)
//    can be found in many places.
//    For example on the Arduino.cc forum.
//    The original author is not know.
// Version 2, Juni 2012, Using Arduino 1.0.1
//     Adapted to be as simple as possible by Arduino.cc user Krodal
// Version 3, Feb 26  2013
//    V3 by louarnold
// Version 4, March 3, 2013, Using Arduino 1.0.3
//    by Arduino.cc user Krodal.
//    Changes by louarnold removed.
//    Scanning addresses changed from 0...127 to 1...119,
//    according to the i2c scanner by Nick Gammon
//    http://www.gammon.com.au/forum/?id=10896
// Version 5, March 28, 2013
//    As version 4, but address scans now to 127.
//    A sensor seems to use address 120.
// Version 6, November 27, 2015.
//    Added waiting for the Leonardo serial communication.
//
//
// This sketch tests the standard 7-bit addresses
// Devices with higher bit address might not be seen properly.
//

#include <Wire.h>
#define pinSCL  23
#define pinSDA 22
#define pinEna 4

void setup()
{
  pinMode(pinEna, OUTPUT);
  digitalWrite(pinEna, HIGH);
  Wire.begin(pinSCL, pinSDA, TWI_FREQUENCY_100K);

  Serial.begin(9600);
  while (!Serial);             // Leonardo: wait for serial monitor
  Serial.println("\nI2C Scanner");
}

void loop()
{
  byte error, address;
  int nDevices;

  Serial.println("Scanning...");

  nDevices = 0;
  for (address = 1; address < 127; address++ )
  {
    // The i2c_scanner uses the return value of
    // the Write.endTransmisstion to see if
    // a device did acknowledge to the address.
    Wire.beginTransmission(address);
    error = Wire.endTransmission();

    if (error == 0)
    {
      Serial.print("I2C device found at address 0x");
      if (address < 16)
        Serial.print("0");
      Serial.print(address, HEX);
      Serial.println("  !");

      nDevices++;
    }
    else if (error == 4)
    {
      Serial.print("Unknow error at address 0x");
      if (address < 16)
        Serial.print("0");
      Serial.println(address, HEX);
    }
  }
  if (nDevices == 0){
    Serial.println("No I2C devices found\n");
    Serial.print("Last address:");
    Serial.println(address);
  }
  else
    Serial.println("done\n");

  delay(5000);           // wait 5 seconds for next scan
}

wire.cpp

/*
    Copyright (c) 2014 RedBearLab, All rights reserved.
    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2.1 of the License, or (at your option) any later version.
    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
    See the GNU Lesser General Public License for more details.
    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
    IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
    CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
    TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
    SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

#include "Wire.h"

/**********************************************************************
name :
function : 
**********************************************************************/
TwoWire::TwoWire() : 
                    RX_BufferHead(0), RX_BufferTail(0),
                    TX_BufferHead(0), TX_BufferTail(0), 
                    Transfer_Addr(0),
                    i2c(),
                    twi_status(UNINITIALIZED)
{
    //do nothing
}
/**********************************************************************
name :
function : 
**********************************************************************/
void TwoWire::begin(uint32_t scl, uint32_t sda, uint32_t speed)
{   
    PinName nrf_sda, nrf_scl;

    nrf_scl = Pin_nRF51822_to_Arduino(scl);
    nrf_sda = Pin_nRF51822_to_Arduino(sda);

    /* Initialize i2c */
    i2c_init(&i2c, nrf_sda, nrf_scl);
    i2c_frequency(&i2c, speed);
    twi_status = UNINITIALIZED;
}
/**********************************************************************
name :
function : 
**********************************************************************/
void TwoWire::begin()
{
    PinName nrf_sda, nrf_scl;

    nrf_scl = Pin_nRF51822_to_Arduino(TWI_SCL);
    nrf_sda = Pin_nRF51822_to_Arduino(TWI_SDA); 
    /* Initialize i2c, default 100KHz */
    i2c_init(&i2c, nrf_sda, nrf_scl);
    twi_status = UNINITIALIZED;
}
/**********************************************************************
name :
function : 
note : address has been shift right one bit, so need to shift left one bit
**********************************************************************/
void TwoWire::beginTransmission( uint8_t address )
{
    Transfer_Addr = (address << 1);
    TX_BufferTail = 0;
    TX_BufferHead = 0;
    twi_status = MASTER_SEND;
}
/**********************************************************************
name :
function : 
**********************************************************************/
void TwoWire::beginTransmission( int address )
{
    beginTransmission( (uint8_t)address );
}
/**********************************************************************
name :
function : 
return : 0 success, -1 no slave, -2 bus busy
**********************************************************************/
int8_t TwoWire::endTransmission( uint8_t stop)
{
    int8_t result=0;

    result = i2c_write(&i2c, Transfer_Addr, (const char *)TX_Buffer, TX_BufferHead, stop);

    TX_BufferHead = 0;
    twi_status = MASTER_IDLE;   

    if(i2c.i2c->EVENTS_ERROR == 1) {
        if (i2c.i2c->ERRORSRC & TWI_ERRORSRC_ANACK_Msk) {
            i2c.i2c->EVENTS_ERROR = 0;
            i2c.i2c->TASKS_STOP   = 1;
            result = I2C_ERROR_NO_SLAVE;
        }
        else if(i2c.i2c->ERRORSRC & TWI_ERRORSRC_DNACK_Msk) {
            i2c.i2c->EVENTS_ERROR = 0;
            i2c.i2c->TASKS_STOP   = 1;
            result = I2C_ERROR_BUS_BUSY;
        }
    }

    if(stop)
        i2c_reset(&i2c);

    return result;
}
/**********************************************************************
name :
function : 
**********************************************************************/
int8_t TwoWire::endTransmission(void)
{
    int8_t result;

    result = endTransmission(1);

    return result;
}
/**********************************************************************
name :
function :
return :   0:full or error status
           1:success
**********************************************************************/
size_t TwoWire::write(uint8_t data)
{
    if(twi_status == MASTER_SEND) { 
        if(TX_BufferHead >= BUFF_MAX_LENGTH) {
            return 1;
        }
        TX_Buffer[TX_BufferHead++] = data;
        return 0;
    }
    else {
        return 1;
    }
}
/**********************************************************************
name :
function : 
return :   0        :   full or error status
           other    :   the true size of write 
**********************************************************************/
size_t TwoWire::write(const uint8_t *data, size_t quantity )
{
    size_t index;

    if( twi_status == MASTER_SEND ) {
        for( index=0; index<quantity; ++index ) {   
            if(TX_BufferHead >= BUFF_MAX_LENGTH) {
                return index;
            }
            TX_Buffer[TX_BufferHead++] = data[index];
        }
    }
    else {
        return 0;
    }

    return quantity;
}
/**********************************************************************
name :
function : 
return :   0        :   error
           other    :   the true size of read 
**********************************************************************/
uint8_t TwoWire::requestFrom(uint8_t addr, uint8_t quantity, uint8_t stop)
{
    uint8_t result;

    Transfer_Addr = (addr << 1);
    if(quantity > BUFF_MAX_LENGTH) {   
        quantity = BUFF_MAX_LENGTH;
    }
    if(quantity > 0 ) {   
        result = i2c_read(&i2c, Transfer_Addr, (char *)RX_Buffer, quantity, stop);
    }
    RX_BufferTail = 0;
    RX_BufferHead = result;

    return result;
}
/**********************************************************************
name :
function : 
**********************************************************************/
uint8_t TwoWire::requestFrom(uint8_t address, uint8_t quantity)
{
    return requestFrom((uint8_t) address, (uint8_t) quantity, (uint8_t) true);
}
/**********************************************************************
name :
function : 
**********************************************************************/
uint8_t TwoWire::requestFrom(int address, int quantity) 
{
    return requestFrom((uint8_t) address, (uint8_t) quantity, (uint8_t) true);
}
/**********************************************************************
name :
function : 
**********************************************************************/
uint8_t TwoWire::requestFrom(int address, int quantity, int sendStop) 
{
    return requestFrom((uint8_t) address, (uint8_t) quantity, (uint8_t) sendStop);
}
/**********************************************************************
name :
function : 
**********************************************************************/
int TwoWire::available(void)
{
    if(RX_BufferTail <= RX_BufferHead) {
        return (RX_BufferHead - RX_BufferTail);
    }
    else {
        return 0;
    }
}
/**********************************************************************
name :
function : 
**********************************************************************/
int TwoWire::read(void)
{
    if(RX_BufferTail < RX_BufferHead) {
        return RX_Buffer[RX_BufferTail++];
    }
    else {
        return -1;
    }
}
/**********************************************************************
name :
function : 
**********************************************************************/
int TwoWire::peek(void)
{
    if(RX_BufferTail < RX_BufferHead) {
        return RX_Buffer[RX_BufferTail];
    }
    else {
        return -1;
    }
}
/**********************************************************************
name :
function : 
**********************************************************************/
void TwoWire::flush(void)
{
    //do nothing
}

TwoWire Wire;

wire.h

/*
    Copyright (c) 2014 RedBearLab, All rights reserved.
    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2.1 of the License, or (at your option) any later version.
    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
    See the GNU Lesser General Public License for more details.
    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
    IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
    CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
    TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
    SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

#ifndef _WIRE_H_
#define _WIRE_H_

#include "WStream.h"
#include "Arduino.h"

#define BUFF_MAX_LENGTH  32

#define TWI_FREQUENCY_100K  100000
#define TWI_FREQUENCY_250K  250000 
#define TWI_FREQUENCY_400K  400000 

class TwoWire : public WStream
{
    public :

        enum TwoWireStatus {
            UNINITIALIZED,
            MASTER_IDLE,
            MASTER_SEND,
            MASTER_RECV,
            SLAVE_IDLE,
            SLAVE_RECV,
            SLAVE_SEND
        };      

    protected : 
        uint8_t RX_Buffer[BUFF_MAX_LENGTH];
        uint8_t RX_BufferHead;
        uint8_t RX_BufferTail;

        uint8_t TX_Buffer[BUFF_MAX_LENGTH];
        uint8_t TX_BufferHead;
        uint8_t TX_BufferTail;

        uint8_t Transfer_Addr;  

        i2c_t   i2c;

        TwoWireStatus twi_status;

    public :
        TwoWire();
        void begin();
        void begin(uint32_t scl_pin, uint32_t sda_pin, uint32_t speed);
        void beginTransmission(uint8_t);
        void beginTransmission(int);

        int8_t endTransmission(void);
        int8_t endTransmission(uint8_t);

        uint8_t requestFrom(uint8_t, uint8_t);
        uint8_t requestFrom(uint8_t, uint8_t, uint8_t);
        uint8_t requestFrom(int, int);
        uint8_t requestFrom(int, int, int);
        virtual size_t write(uint8_t);
        virtual size_t write(const uint8_t *, size_t);
        virtual int available(void);
        virtual int read(void);
        virtual int peek(void);
        virtual void flush(void);

        inline size_t write(unsigned long n) { return write((uint8_t)n); }
        inline size_t write(long n) { return write((uint8_t)n); }
        inline size_t write(unsigned int n) { return write((uint8_t)n); }
        inline size_t write(int n) { return write((uint8_t)n); }

        using Print::write; 
};

extern TwoWire Wire;

#endif
1vav commented 8 years ago

So there's a difference between Wire.h and wire.h as far as I know, you're include and actual file don't match our seems to me. I use the default Wire.h not the mbed wire.h. Honestly I don't remember where I downloaded from.

Also the address << 1, try changing that to just address in the begin transmission function if you use that library. On Apr 7, 2016 5:23 PM, "Lilium JSN" notifications@github.com wrote:

Thanks for your answer. To start with, can you please verify what Wire files' version did you use? It seems that this one for example ( https://developer.mbed.org/teams/RedBearLab/code/I2C_Demo/file/0298ffee8eba/wire.cpp) is not using pin_transform. Total resistor pullup value is 10K and i've checked the schematics a hundred times today. arduinoPin23 should be nrfP0_5 and arduinoPin22 should be nrfP04. Here is my code: .ino_

// -------------------------------------- // i2c_scanner // // Version 1 // This program (or code that looks like it) // can be found in many places. // For example on the Arduino.cc forum. // The original author is not know. // Version 2, Juni 2012, Using Arduino 1.0.1 // Adapted to be as simple as possible by Arduino.cc user Krodal // Version 3, Feb 26 2013 // V3 by louarnold // Version 4, March 3, 2013, Using Arduino 1.0.3 // by Arduino.cc user Krodal. // Changes by louarnold removed. // Scanning addresses changed from 0...127 to 1...119, // according to the i2c scanner by Nick Gammon // http://www.gammon.com.au/forum/?id=10896 // Version 5, March 28, 2013 // As version 4, but address scans now to 127. // A sensor seems to use address 120. // Version 6, November 27, 2015. // Added waiting for the Leonardo serial communication. // // // This sketch tests the standard 7-bit addresses // Devices with higher bit address might not be seen properly. //

include

define pinSCL 23

define pinSDA 22

define pinEna 4

void setup() { pinMode(pinEna, OUTPUT); digitalWrite(pinEna, HIGH); Wire.begin(pinSCL, pinSDA, TWI_FREQUENCY_100K);

Serial.begin(9600); while (!Serial); // Leonardo: wait for serial monitor Serial.println("\nI2C Scanner"); }

void loop() { byte error, address; int nDevices;

Serial.println("Scanning...");

nDevices = 0; for (address = 1; address < 127; address++ ) { // The i2c_scanner uses the return value of // the Write.endTransmisstion to see if // a device did acknowledge to the address. Wire.beginTransmission(address); error = Wire.endTransmission();

if (error == 0)
{
  Serial.print("I2C device found at address 0x");
  if (address < 16)
    Serial.print("0");
  Serial.print(address, HEX);
  Serial.println("  !");

  nDevices++;
}
else if (error == 4)
{
  Serial.print("Unknow error at address 0x");
  if (address < 16)
    Serial.print("0");
  Serial.println(address, HEX);
}

} if (nDevices == 0){ Serial.println("No I2C devices found\n"); Serial.print("Last address:"); Serial.println(address); } else Serial.println("done\n");

delay(5000); // wait 5 seconds for next scan }

wire.cpp

/ Copyright (c) 2014 RedBearLab, All rights reserved. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. /

include "Wire.h"

/** name : function : _/ TwoWire::TwoWire() : RX_BufferHead(0), RX_BufferTail(0), TX_BufferHead(0), TX_BufferTail(0), Transfer_Addr(0), i2c(), twi_status(UNINITIALIZED) { //do nothing } /_ name : function : **/ void TwoWire::begin(uint32_t scl, uint32_t sda, uint32_t speed) { PinName nrf_sda, nrf_scl;

nrf_scl = Pin_nRF51822_to_Arduino(scl);
nrf_sda = Pin_nRF51822_to_Arduino(sda);

/* Initialize i2c */
i2c_init(&i2c, nrf_sda, nrf_scl);
i2c_frequency(&i2c, speed);
twi_status = UNINITIALIZED;

} /** name : function : **/ void TwoWire::begin() { PinName nrf_sda, nrf_scl;

nrf_scl = Pin_nRF51822_to_Arduino(TWI_SCL);
nrf_sda = Pin_nRF51822_to_Arduino(TWI_SDA);
/* Initialize i2c, default 100KHz */
i2c_init(&i2c, nrf_sda, nrf_scl);
twi_status = UNINITIALIZED;

} /** name : function : note : address has been shift right one bit, so need to shift left one bit _/ void TwoWire::beginTransmission( uint8_t address ) { Transfer_Addr = (address << 1); TX_BufferTail = 0; TX_BufferHead = 0; twi_status = MASTER_SEND; } /_ name : function : _/ void TwoWire::beginTransmission( int address ) { beginTransmission( (uint8_t)address ); } /_ name : function : return : 0 success, -1 no slave, -2 bus busy **/ int8_t TwoWire::endTransmission( uint8_t stop) { int8_t result=0;

result = i2c_write(&i2c, Transfer_Addr, (const char *)TX_Buffer, TX_BufferHead, stop);

TX_BufferHead = 0;
twi_status = MASTER_IDLE;

if(i2c.i2c->EVENTS_ERROR == 1) {
    if (i2c.i2c->ERRORSRC & TWI_ERRORSRC_ANACK_Msk) {
        i2c.i2c->EVENTS_ERROR = 0;
        i2c.i2c->TASKS_STOP   = 1;
        result = I2C_ERROR_NO_SLAVE;
    }
    else if(i2c.i2c->ERRORSRC & TWI_ERRORSRC_DNACK_Msk) {
        i2c.i2c->EVENTS_ERROR = 0;
        i2c.i2c->TASKS_STOP   = 1;
        result = I2C_ERROR_BUS_BUSY;
    }
}

if(stop)
    i2c_reset(&i2c);

return result;

} /** name : function : **/ int8_t TwoWire::endTransmission(void) { int8_t result;

result = endTransmission(1);

return result;

} /** name : function : return : 0:full or error status 1:success _/ size_t TwoWire::write(uint8_t data) { if(twi_status == MASTER_SEND) { if(TX_BufferHead >= BUFF_MAX_LENGTH) { return 1; } TX_Buffer[TX_BufferHead++] = data; return 0; } else { return 1; } } /_ name : function : return : 0 : full or error status other : the true size of write **/ size_t TwoWire::write(const uint8_t *data, size_t quantity ) { size_t index;

if( twi_status == MASTER_SEND ) {
    for( index=0; index<quantity; ++index ) {
        if(TX_BufferHead >= BUFF_MAX_LENGTH) {
            return index;
        }
        TX_Buffer[TX_BufferHead++] = data[index];
    }
}
else {
    return 0;
}

return quantity;

} /** name : function : return : 0 : error other : the true size of read **/ uint8_t TwoWire::requestFrom(uint8_t addr, uint8_t quantity, uint8_t stop) { uint8_t result;

Transfer_Addr = (addr << 1);
if(quantity > BUFF_MAX_LENGTH) {
    quantity = BUFF_MAX_LENGTH;
}
if(quantity > 0 ) {
    result = i2c_read(&i2c, Transfer_Addr, (char *)RX_Buffer, quantity, stop);
}
RX_BufferTail = 0;
RX_BufferHead = result;

return result;

} /** name : function : _/ uint8_t TwoWire::requestFrom(uint8_t address, uint8_t quantity) { return requestFrom((uint8_t) address, (uint8_t) quantity, (uint8_t) true); } /_ name : function : _/ uint8_t TwoWire::requestFrom(int address, int quantity) { return requestFrom((uint8_t) address, (uint8_t) quantity, (uint8_t) true); } /_ name : function : _/ uint8_t TwoWire::requestFrom(int address, int quantity, int sendStop) { return requestFrom((uint8_t) address, (uint8_t) quantity, (uint8_t) sendStop); } /_ name : function : _/ int TwoWire::available(void) { if(RX_BufferTail <= RX_BufferHead) { return (RX_BufferHead - RX_BufferTail); } else { return 0; } } /_ name : function : _/ int TwoWire::read(void) { if(RX_BufferTail < RX_BufferHead) { return RX_Buffer[RX_BufferTail++]; } else { return -1; } } /_ name : function : _/ int TwoWire::peek(void) { if(RX_BufferTail < RX_BufferHead) { return RX_Buffer[RX_BufferTail]; } else { return -1; } } /_ name : function : **/ void TwoWire::flush(void) { //do nothing }

TwoWire Wire;

wire.h

/ Copyright (c) 2014 RedBearLab, All rights reserved. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. /

ifndef _WIREH

define _WIREH

include "WStream.h"

include "Arduino.h"

define BUFF_MAX_LENGTH 32

define TWI_FREQUENCY_100K 100000

define TWI_FREQUENCY_250K 250000

define TWI_FREQUENCY_400K 400000

class TwoWire : public WStream { public :

    enum TwoWireStatus {
        UNINITIALIZED,
        MASTER_IDLE,
        MASTER_SEND,
        MASTER_RECV,
        SLAVE_IDLE,
        SLAVE_RECV,
        SLAVE_SEND
    };

protected :
    uint8_t RX_Buffer[BUFF_MAX_LENGTH];
    uint8_t RX_BufferHead;
    uint8_t RX_BufferTail;

    uint8_t TX_Buffer[BUFF_MAX_LENGTH];
    uint8_t TX_BufferHead;
    uint8_t TX_BufferTail;

    uint8_t Transfer_Addr;

    i2c_t   i2c;

    TwoWireStatus twi_status;

public :
    TwoWire();
    void begin();
    void begin(uint32_t scl_pin, uint32_t sda_pin, uint32_t speed);
    void beginTransmission(uint8_t);
    void beginTransmission(int);

    int8_t endTransmission(void);
    int8_t endTransmission(uint8_t);

    uint8_t requestFrom(uint8_t, uint8_t);
    uint8_t requestFrom(uint8_t, uint8_t, uint8_t);
    uint8_t requestFrom(int, int);
    uint8_t requestFrom(int, int, int);
    virtual size_t write(uint8_t);
    virtual size_t write(const uint8_t *, size_t);
    virtual int available(void);
    virtual int read(void);
    virtual int peek(void);
    virtual void flush(void);

    inline size_t write(unsigned long n) { return write((uint8_t)n); }
    inline size_t write(long n) { return write((uint8_t)n); }
    inline size_t write(unsigned int n) { return write((uint8_t)n); }
    inline size_t write(int n) { return write((uint8_t)n); }

    using Print::write;

};

extern TwoWire Wire;

endif

— You are receiving this because you were mentioned. Reply to this email directly or view it on GitHub https://github.com/RedBearLab/nRF51822-Arduino/issues/38#issuecomment-207147571