Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependencies: mbed BufferedSerial Servo2 PCT2075 I2CEeprom FastPWM
Diff: i2c_bit_banged.cpp
- Revision:
- 3:43cb067ecd00
- Parent:
- 2:8e7b51353f32
- Child:
- 4:28cc0cf01570
--- a/i2c_bit_banged.cpp Mon Jun 08 13:46:52 2020 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,466 +0,0 @@
-#include "mbed.h"
-#include "Alternator.h"
-
-#define I2CTEST
-
-#ifdef TARGET_NUCLEO_L432KC //
-#ifdef I2CTEST
-extern Serial pc;
-extern I2C i2c;
-const int ACK = 1; // but acknowledge is 0, NAK is 1 6/6/2020 think this should be 1
-
-#else
-
-extern Serial pc;
-DigitalInOut SDA (D4); // Horrible bodge to get i2c working using bit banging.
-DigitalInOut SCL (D5); // DigitalInOut do not work as you might expect. Fine if used only as OpenDrain opuputs though!
-DigitalIn SDA_IN (A4); // That means paralleling up with two other pins as inputs
-DigitalIn SCL_IN (A5); // This works but is a pain. Inbuilt I2C should have worked but never does on small boards with 32 pin cpu.
-const int ACK = 0; // but acknowledge is 0, NAK is 1
-#endif
-#ifdef TARGET_NUCLEO_F401RE //
-extern BufferedSerial pc;
-extern I2C i2c;
-const int ACK = 1; // but acknowledge is 0, NAK is 1
-#endif
-#endif
-const int _24LC_rd = 0xa1; // set bit 0 for read, clear bit 0 for write
-const int _24LC_wr = 0xa0; // set bit 0 for read, clear bit 0 for write
-
-
-/*struct optpar {
- int min, max, def; // min, max, default
- const char * t; // description
-} ;*/
-struct optpar option_list2[] = {
- {0, 100, 1, "max pwm% @ Eng RPM 0, 0 to 100"},
- {0, 100, 1, "max pwm% @ Eng RPM 500, 0 to 100"},
- {0, 100, 1, "max pwm% @ Eng RPM 1000, 0 to 100"},
- {0, 100, 1, "max pwm% @ Eng RPM 1500, 0 to 100"},
- {0, 100, 1, "max pwm% @ Eng RPM 2000, 0 to 100"},
- {0, 100, 10, "max pwm% @ Eng RPM 2500, 0 to 100"},
- {0, 100, 60, "max pwm% @ Eng RPM 3000, 0 to 100"},
- {0, 100, 70, "max pwm% @ Eng RPM 3500, 0 to 100"},
- {0, 100, 60, "max pwm% @ Eng RPM 4000, 0 to 100"},
- {0, 100, 50, "max pwm% @ Eng RPM 4500, 0 to 100"},
- {0, 100, 40, "max pwm% @ Eng RPM 5000, 0 to 100"},
- {0, 100, 33, "max pwm% @ Eng RPM 5500, 0 to 100"},
- {0, 100, 30, "max pwm% @ Eng RPM 6000, 0 to 100"},
- {0, 100, 30, "max pwm% @ Eng RPM 6500, 0 to 100"},
- {0, 100, 40, "max pwm% @ Eng RPM 7000, 0 to 100"},
- {0, 100, 50, "max pwm% @ Eng RPM 7500, 0 to 100"},
- {0, 100, 60, "max pwm% @ Eng RPM 8000, 0 to 100"},
- {0, 100, 0, "Future 2"},
- {0, 100, 0, "Future 3"},
- {0, 100, 0, "Future 4"},
- {0, 100, 0, "Future 5"},
- {0, 100, 0, "Future 6"},
- {0, 100, 0, "Future 7"},
- {0, 100, 0, "Future 8"},
- {0, 100, 0, "Future 9"},
- {0, 100, 0, "Future 10"},
- {0, 100, 0, "Future 11"},
- {0, 100, 0, "Future 12"},
- {0, 100, 0, "Future 13"},
-} ;
-
-const int numof_eeprom_options2 = sizeof(option_list2) / sizeof (struct optpar);
-
-bool wr_24LC64 (int start_addr, char * source, int length) ; // think this works
-bool rd_24LC64 (int start_addr, char * source, int length) ; // think this works
-
-
-
-eeprom_settings user_settings ;
-
-eeprom_settings::eeprom_settings () {}
-
-bool eeprom_settings::set_defaults () {
- for (int i = 0; i < numof_eeprom_options2; i++)
- settings[i] = option_list2[i].def; // Load defaults and 'Save Settings'
- return save ();
-}
-
-char eeprom_settings::rd (uint32_t i) { // Read one setup char value from private buffer 'settings'
- if (i > 31) {
- pc.printf ("ERROR Attempt to read setting %d\r\n", i);
- return 0;
- }
- return settings[i];
-}
-
-bool eeprom_settings::rd (char * c, uint32_t i) { // Read one setup char value from private buffer 'settings'
- if (i > 31) {
- pc.printf ("ERROR Attempt to read setting %d\r\n", i);
- return false;
- }
- *c = settings[i];
- return true;
-}
-
-bool eeprom_settings::wr (char c, uint32_t i) { // Write one setup char value to private buffer 'settings'
- if (i > 31)
- return false;
- settings[i] = c;
- return true;
-}
-
-/*double eeprom_settings::get_pwm (int rpm) {
- int p = rpm * lut_size;
- p /= 8000; // 8000 is upper RPM limit, p now scaled to sizeof lut
- if (p < 0) p = 0; // point to first
- if (p >= lut_size) p = lut_size - 1; // point to last
-// pc.printf ("In get_pwm, rpm = %d, lut entry = %d, pwm = %d\r\n", rpm, p, max_pwm_lut[p]);
- return max_pwm_lut[p];
-}*/
-
-/*void eeprom_settings::build_lut () {
- int ptr = 0;
- int range, i;
- double acc = 0.0, incr = 0.0;
- for (i = 0; i < 8; i++) {
- range = user_settings.rd(i+1) - user_settings.rd(i); // range now change in percent between two 'n'000 RPMs
- incr = (double)range;
- incr /= 100.0; // percent
- incr /= lut_seg_size;
- for(int j = 0; j < lut_seg_size; j++) {
- max_pwm_lut[ptr++] = acc;
- acc += incr;
- }
- }
- max_pwm_lut[ptr] = (int)acc;
- pc.printf ("At end of build_lut ptr=%d\r\n", ptr);
- range = 0;
-
- while (range < ptr) {
- for (i = 0; i < 8; i++) {
- pc.printf ("%.3f\t", max_pwm_lut[range++]);
- }
- pc.printf ("\r\n");
- }
- pc.printf ("lut_size = %d\r\n", lut_size);
-
-}*/
-
-bool eeprom_settings::load () { // Get 'settings' buffer from EEPROM
- bool rv ;
- rv = rd_24LC64 (eeprom_page * 32, settings, 32); // Can now build lookup table
-//Apr2020 build_lut ();
- return rv;
-}
-
-bool eeprom_settings::save () { // Write 'settings' buffer to EEPROM
- return wr_24LC64 (eeprom_page * 32, settings, 32);
-}
-
-
-//#ifdef TARGET_NUCLEO_L432KC //
-
-/**
-* bool i2c_init(void) {
-*
-* Init function. Needs to be called once in the beginning.
-* Returns false if SDA or SCL are low, which probably means
-* a I2C bus lockup or that the lines are not pulled up.
-*/
-bool i2c_init(void) {
-#ifdef TARGET_NUCLEO_L432KC //
-#ifndef I2CTEST
- SDA.output();
- SCL.output();
- SDA.mode(OpenDrain);
- SCL.mode(OpenDrain); // Device may pull clock lo to indicate to master
- SDA = 0;
- SCL = 0;
- wait_us (1);
- SDA = 1;
- wait_us (1);
- SCL = 1;
- wait_us (1);
- if (SCL_IN == 0 || SDA_IN == 0) return false;
-#endif
-#endif
-#ifdef TARGET_NUCLEO_F401RE //
-// return i2c.init () ; // class has no member "init"
-#endif
- return true;
-}
-
-/**
-* During data transfer, the data line must remain
-* stable whenever the clock line is high. Changes in
-* the data line while the clock line is high will be
-* interpreted as a Start or Stop condition
-*
-* A high-to-low transition of the SDA line while the clock
-* (SCL) is high determines a Start condition. All
-* commands must be preceded by a Start condition.
-*/
-int i2c_start () { // Should be Both hi, start takes SDA low
-#ifdef TARGET_NUCLEO_L432KC //
-#ifndef I2CTEST
- int rv = 0;
- if (SDA_IN == 0 ) {
- rv |= 1; // Fault - SDA was lo on entry
- SDA = 1;
- wait_us (1);
- }
- if (SCL == 0 ) {
- rv |= 2; // Fault - SCL was lo on entry
- SCL = 1;
- wait_us (1);
- }
- SDA = 0; // Take SDA lo
- wait_us (1);
- SCL = 0;
- wait_us (1);
- return rv; // Returns 0 on success, 1 with SDA fault, 2 with SCL fault, 3 with SDA and SCL fault
-#else
- i2c.start () ;
- return 0;
-
-#endif
-#endif
-#ifdef TARGET_NUCLEO_F401RE //
- i2c.start () ;
- return 0;
-#endif
-}
-
-/**
-* During data transfer, the data line must remain
-* stable whenever the clock line is high. Changes in
-* the data line while the clock line is high will be
-* interpreted as a Start or Stop condition
-*
-* A low-to-high transition of the SDA line while the clock
-* (SCL) is high determines a Stop condition. All
-* operations must be ended with a Stop condition.
-*/
-int i2c_stop () { // Should be SDA=0, SCL=1, start takes SDA hi
-#ifdef TARGET_NUCLEO_L432KC //
-#ifdef I2CTEST
- i2c.stop () ;
- return 0;
-#else
- int rv = 0;
- SDA = 0; // Pull SDA to 0
- wait_us (1);
- if (SCL_IN != 0) {
- pc.printf ("SCL 1 on entry to stop\r\n");
- SCL = 0; // pull SCL to 0 if not there already
- wait_us (1);
- }
- SCL = 1;
- wait_us (1);
- if (SCL_IN == 0)
- pc.printf ("SCL stuck lo in stop\r\n");
- SDA = 1;
- wait_us (1);
- if (SDA_IN == 0)
- pc.printf ("SDA stuck lo in stop\r\n");
- return rv; // Returns 0 on success, 1 with SDA fault, 2 with SCL fault, 3 with SDA and SCL fault
-#endif
-#endif
-#ifdef TARGET_NUCLEO_F401RE //
- i2c.stop () ;
- return 0;
-#endif
-}
-
-#ifdef TARGET_NUCLEO_L432KC //
-#ifndef I2CTEST
-void jclk (int bit) {
- SCL = bit;
- wait_us (1);
-}
-
-void jclkout () {
- wait_us (1);
- SCL = 1;
- wait_us (1);
- SCL = 0;
- wait_us (1);
-}
-#endif
-#endif
-
-int i2c_write (int d) {
-#ifdef TARGET_NUCLEO_L432KC //
-#ifdef I2CTEST
- return i2c.write (d);
-#else
- int ackbit = 0;
- if (SCL_IN != 0) {
- pc.printf ("SCL hi on entry to write\r\n");
- jclk (0);
- }
- for (int i = 0x80; i != 0; i >>= 1) { // bit out msb first
- if ((d & i) == 0) SDA = 0;
- else SDA = 1;
- jclkout (); // SCL ____---____
- }
- SDA = 1; // Release data to allow remote device to pull lo for ACK or not
- jclk (1); // SCL = 1
- ackbit = SDA_IN; // read in ack bit
- jclk (0); // SCL = 0
-// pc.printf ("wr 0x%x %s\r\n", d, ackbit == 0 ? "ACK" : "nak");
- return ackbit; // 0 for acknowledged ACK, 1 for NAK
-#endif
-#endif
-#ifdef TARGET_NUCLEO_F401RE //
- return i2c.write (d);
-#endif
-}
-
-
-
-
-int i2c_read (int acknak) { // acknak indicates if the byte is to be acknowledged (0 = acknowledge)
-#ifdef TARGET_NUCLEO_L432KC //
-#ifdef I2CTEST
- return i2c.read (acknak) ;
-#else
- int result = 0; // SCL should be 1 on entry
- SDA = 1; // Master released SDA
- if (SCL_IN != 0) pc.printf ("SCL hi arriving at read\r\n");
- wait_us (2);
- for (int i = 0; i < 8; i++) {
- result <<= 1;
- jclk (1);
- if (SDA_IN != 0) result |= 1;
- jclk (0);
- }
- if (acknak != 0 && acknak != 1)
- pc.printf ("Bad acknak in 12c_read %d\r\n", acknak);
- if (acknak == 0) SDA = 0;
- else SDA = 1;
- jclkout (); // clock out the ACK bit __--__
-// pc.printf ("rd 0x%x %s\r\n", result, acknak == 0 ? "ACK" : "nak");
- return result; // Always ? nah
-#endif
-#endif
-#ifdef TARGET_NUCLEO_F401RE //
- return i2c.read (acknak) ;
-#endif
-}
-
-int check_24LC64 () { // Call from near top of main() to init i2c bus
- int last_found = 0, q, e; // Note address bits 3-1 to match addr pins on device
- for (int i = 0; i < 255; i += 2) { // Search for devices at all possible i2c addresses
- e = i2c_start();
- if (e) pc.putc(',');
- q = i2c_write(i); // may return error code 2 when no start issued
- if (q == ACK) {
- pc.printf ("I2C device found at 0x%x\r\n", i);
- last_found = i;
- wait_ms (5);
- }
- i2c_stop();
- }
- return last_found;
-}
-
-
-
-
-
-
-
-
-bool ack_poll () { // wait short while for any previous memory operation to complete
- const int poll_tries = 40;
- int poll_count = 0;
- bool i2cfree = false;
- while (poll_count++ < poll_tries && !i2cfree) {
- i2c_start ();
- if (i2c_write(_24LC_wr) == ACK)
- i2cfree = true;
- else
- wait_ms (1);
- }
-// pc.printf ("ack_poll, count = %d, i2cfree = %s\r\n", poll_count, i2cfree ? "true" : "false");
- return i2cfree;
-}
-
-/**bool set_24LC64_internal_address (int start_addr) {
-*
-*
-*
-*/
-bool set_24LC64_internal_address (int start_addr) {
- if (!ack_poll())
- {
- pc.printf ("Err in set_24LC64_internal_address, no ACK writing device address byte\r\n");
- i2c_stop();
- return false;
- }
- int err = 0;
- if (i2c_write(start_addr >> 8) != ACK) err++;
- if (i2c_write(start_addr & 0xff) != ACK) err++;
- if (err) {
- pc.printf ("In set_24LC64_internal_address, Believe Device present, failed in writing 2 mem addr bytes %d\r\n", err);
- i2c_stop();
- return false;
- }
-// pc.printf ("GOOD set_24LC64_internal_address %d\r\n", start_addr);
- return true;
-}
-
-bool wr_24LC64 (int start_addr, char * source, int length) { // think this works
- int err = 0;
- if(length < 1 || length > 32) {
- pc.printf ("Length out of range %d in wr_24LC64\r\n", length);
- return false;
- }
- ack_poll ();
- if (!set_24LC64_internal_address (start_addr)) {
- pc.printf ("In wr_24LC64, Believe Device present, failed in writing 2 mem addr bytes %d\r\n", err);
- return false;
- }
- while(length--)
- if (i2c_write(*source++) != ACK)
- err++;
-// err += i2c_write(*source++);
- i2c_stop();
- if (err) {
- pc.printf ("in wr_24LC64, device thought good, mem addr write worked, failed writing string\r\n");
- return false;
- }
-// pc.printf ("In wr_24LC64 No Errors Found!\r\n");
- return true;
-}
-
-bool rd_24LC64 (int start_addr, char * dest, int length) {
- int acknak = ACK;
- if(length < 1)
- return false;
- if (!set_24LC64_internal_address (start_addr)) {
- pc.printf ("In rd_24LC64, failed to set_ramaddr\r\n");
- return false;
- }
- i2c_start();
- if (i2c_write(_24LC_rd) != ACK) {
- pc.printf ("Errors in rd_24LC64 sending 24LC_rd\r\n");
- return false;
- }
- while(length--) {
- if(length == 0)
- acknak = 1;
- *dest++ = i2c_read(acknak);
- }
- i2c_stop();
- return true;
-}
-
-
-
-
-
-
-
-
-
-
-
-