Add I2CSlave to ov580 master.

Dependencies:   MorseGenerator2

main.cpp

Committer:
jasoncha
Date:
2019-05-02
Revision:
26:9ad740976a72
Parent:
25:eac4de6661a9

File content as of revision 26:9ad740976a72:

#define TWIS1_ENABLED 1
#define TWIS0_ENABLED 0
#define TWIS_ENABLED 1
#define TWI0_ENABLED 1
#define TWI1_ENABLED 0
#define TWI0_USE_EASY_DMA 1
#define TWI1_USE_EASY_DMA 1
#define TWI_DEFAULT_CONFIG_FREQUENCY 104857600
#define ARDUINO_A4_PIN  14
#define ARDUINO_A5_PIN  15


#include "mbed.h"
#include "MorseGenerator.h"
#include "SEGGER_RTT.h"
//#include <nrfx_config.h>  need SDK config instead
//#include "sdk_config.h" not needed now

/*
FEATURE REQUIREMENTS

-   I2C write occurs on falling edge of strobe pulse to prevent unknown states

-   Stack check occurs on leading edge of strobe pulse to ensure strobes are
    set correctly

-   Reoccuring enable from app that will prevent the emitters from remaining
    on if the app crashes and a turn off command isn't sent
    - Can be a counter on the emitter enable > threshold
    - Better if it's a counter based on reads from the fault register

-Flood/Dot tagging indicated on GPIO3 / PWM0
    - 0 Flood
    - 1 DOT

-Fault indication on GPIO4 / PWM1 to indicate to app to reboot
    - 0 OK
    - 1 Fault/Reboot

I2C write commands
Reg:        Information             Condition
0x0000      Emitter enable          0x00        Emitters off
                                    0x01        Dot on
                                    0x10        Flood on
                                    0x11        Flood / Dot on

0x0001      Dot fault               Read from LM36011

0x0002      Dot Current             0x00 - level_dot_max

0x0003      Flood Fault             Read from LM36011

0x0004      Flood Current           0x00 - level_flood_max

0x0005      Fault register          bit[0]      KILL_VCSEL fault
                                    bit[1]      dot fault
                                    bit[2]      flood fault
                                    bit[3]      unstacked fault
                                    bit[4]      ?not in app fault?
                                    bit[5-7]    unused


0x0006      Version number          0x70        = version 7.0

*/
/*          ERROR CHECKING      */

#if (TWIS0_ENABLED == 1)
#error TWIS0 is congigured wrong
#endif

#if (TWIS1_ENABLED == 0)
#error TWIS1 is off
#endif

#if (TWIS_ENABLED == 0)
#error TWIS is off
#endif

#if (TWI0_ENABLED == 0)
#error TWI0 is off
#endif

#if (TWI1_ENABLED == 1)
#error TWI1 is congigured wrong
#endif

/*          DEFINES         */

static string version_number = "9";



// define pins for I2C
#define dot_sda p2
#define dot_scl p4
#define flood_sda p28
#define flood_scl p3
#define ov580_sda p30
#define ov580_scl p31

// define strobe pins
#define strobe_flood p23        // strobe0
#define strobe_dot p24          // strobe1

// define pmw pins
#define pwm_1_pin p29
#define pwm_0_pin p5

// define stacked irq pin
#define stacked_irq_pin p11

// define silego enable pin
#define silego_en_pin p26           // needs to be pulled high for Silego

// define dot/flood status pin
#define dot_flood_status_pin p27

// define VCSEL Fault
#define vcselFault_pin p25

// define LED pins
#define ledRed_pin p12
#define ledGreen_pin p17
#define ledBlue_pin p13


static float dot_zero_ms = 295;
static float dot_one_ms = 410;
static float dot_two_ms = 354;
static float dot_three_ms = 295;
static float dot_four_ms = 295;
static float dot_five_ms = 295;
static float flood_zero_ms = 360;
static float flood_one_ms = 900;
static float flood_two_ms = 540;
static float flood_three_ms = 360;
static float flood_four_ms = 360;
static float flood_five_ms = 360;

/*          THREAD          */
EventQueue queue;

/*          TIMOUT          */
Timeout dot_timeout;
Timeout flood_timeout;
Timeout app_timeout;

/*          Timers          */
Timer dot_timer;
Timer flood_timer;

/*          INTERRUPTS      */
//create interupts
InterruptIn int_strobe_dot(strobe_dot);
InterruptIn int_strobe_flood(strobe_flood);

/*          I/O            */
// initialize LEDs
DigitalOut red(ledRed_pin,1);
DigitalOut green(ledGreen_pin,1);
DigitalOut blue(ledBlue_pin,1);

// Initialize outputs
DigitalOut pwm_0_output(pwm_0_pin,0);          // GPIO 3
DigitalOut pwm_1_output(pwm_1_pin,0);          // GPIO 4

// Silego
DigitalOut silego(silego_en_pin,1);     // initialize on

// Initialize inputs
DigitalIn strobe0(strobe_flood,PullNone);
DigitalIn strobe1(strobe_dot,PullNone);
DigitalIn vcselFault(vcselFault_pin, PullNone);
//DigitalIn killVcsel(p26,PullNone);


/*          REGISTERS       */
static uint8_t LM36011_addr = 0x64 << 1;  //0xC8
int NRF_I2CSlave_addr = 0x20;
int NRF_I2CSlave_frequency = 300000;


// register names
static uint8_t enable_reg = 0x01;
static uint8_t configuration_reg = 0x02;
static uint8_t brightness_reg = 0x03;
static uint8_t torch_reg = 0x04;
static uint8_t flags_reg = 0x05;
//static uint8_t device_id_reset_reg = 0x06;

// register settings
static uint8_t enable_ir = 0x05;
static uint8_t disable_ir = 0x20;
static uint8_t enable_flash_timeout = 0x01;
const int thermal_scale_back = 0x08;
const int thermal_shutdown = 0x10;

// level settings
float divisor = 11.7;       // Current / 11.7 = Decimal
float dot_current_setting = dot_five_ms;
float flood_current_setting = flood_five_ms;
uint32_t level_dot_max_dec = uint32_t(dot_current_setting/divisor);
uint32_t level_flood_max_dec = uint32_t(flood_current_setting/divisor);

uint8_t level_dot_max =
    (((level_dot_max_dec / 16) << 4) & 0xf0) |
    ((level_dot_max_dec % 16) & 0x0f);
uint8_t level_flood_max =
    (((level_flood_max_dec / 16) << 4) & 0xf0) |
    ((level_flood_max_dec % 16) & 0x0f);


char lm_on[2] = {enable_reg,enable_ir};
char lm_off[2] = {enable_reg,disable_ir};
char lmSafety[2] = {configuration_reg,enable_flash_timeout};

//char data_read[6];

char flashBrightness_dot[2] = {brightness_reg,level_dot_max};
char flashBrightness_flood[2] = {brightness_reg,level_flood_max};
char torchBrightness_both[2] = {torch_reg,0x5F};

/*          I2C             */
I2CSlave ov580_I2C(ov580_sda,ov580_scl);
I2C flood_I2C(flood_sda,flood_scl);
I2C dot_I2C(dot_sda,dot_scl);


/*          VARIABLES       */
bool stacked = false;
bool emitter_status_dot = false;
char rcv_buffer[3] = {0,0,0};
int dot_counter = 0;
bool dot_on = false;
int flood_counter = 0;
bool flood_on = false;
bool once = false;
bool in_app = false;
int app_counts_required = 10;
int stacked_counter = 0;
bool read_fail;

#define MY_BUF_SIZE 1

int i2c_recv = 0;
char i2c_tx_buff[MY_BUF_SIZE];
char i2c_rx_buff[MY_BUF_SIZE];
char *i2c_tx_buff_ptr =  (char *)0x20000000;
char *i2c_rx_buff_ptr =  (char *)0x20000008;
char i2c_tx_data = 0x55;
char i2c_rx_data = 0x00;

int dot_timer_number;
int flood_timer_number;

/*          FUNCTIONS       */
void silego_check_status()
{
    if(pwm_1_output) {
        silego = 0;
        wait(.5);
        silego = 1;
    }
}

/*
void flood_check_status()
{
    //int read_fail = flood_I2C.read(LM36011_addr,data_read,6,false);
    //if(read_fail) {
    //    red = 0;
    //} else {
        
        if ((data_read[5]&thermal_shutdown) != 0) {
            red = 0;
        } else if((data_read[5]&thermal_scale_back) != 0) {
            red = !red;
        } else {
     //       red = 1;
    //    }
    //}
    //silego_check_status();
}

void dot_check_status()
{
    //int read_fail = dot_I2C.read(LM36011_addr,data_read,6,false);
    //if(read_fail) {
     //   green = 0;
    //} else {
        
        if ((data_read[5]&thermal_shutdown) != 0) {
            green = 0;
        } else if((data_read[5]&thermal_scale_back) != 0) {
            green = !green;
        } else {
      //      green = 1;
      //  }
    //}
    //silego_check_status();
}
*/

// WAI
void write_off()
{
    dot_I2C.write(LM36011_addr,lm_off,2,false);
    flood_I2C.write(LM36011_addr,lm_off,2,false);
}

// WAI
void write_dot()
{
    flood_I2C.write(LM36011_addr,lm_off,2,false);
    //flood_check_status();
    dot_I2C.write(LM36011_addr,lm_on,2,false);
}

// WAI
void write_flood()
{
    dot_I2C.write(LM36011_addr,lm_off,2,false);
    //dot_check_status();
    flood_I2C.write(LM36011_addr,lm_on,2,false);
}

// WAI
void write_pulsed()
{
    if(emitter_status_dot) {
        write_dot();
    } else {
        write_flood();
    }
}

// WAI
void write_once()
{
    if(in_app) {
        if(stacked_counter > app_counts_required) {
            write_pulsed();
            write_pulsed();
        } else {
            if(dot_on) {
                write_dot();
                write_dot();
            } else if(flood_on) {
                write_flood();
                write_flood();
            } else {
                write_off();
                write_off();
            }
        }
    } else {
        write_off();
        write_off();
    }
}

void dot_watchdog()
{
    dot_on = false;
    dot_counter = 0;
    stacked_counter = 0;
    stacked = false;
    queue.call(&write_once);
}

void flood_watchdog()
{
    flood_on = false;
    flood_counter = 0;
    stacked_counter = 0;
    stacked = false;
    queue.call(&write_once);
}

void app_watchdog()
{
    in_app = false;
    dot_watchdog();
    flood_watchdog();
}

void dot_falling_edge()
{
    dot_timer_number = dot_timer.read_us();

    if(stacked) {
        emitter_status_dot = !emitter_status_dot;
    } else {
        emitter_status_dot = dot_on;
    }
    // indicate status dot
    pwm_0_output = emitter_status_dot;
    // indicate VCSEL fault if it exists
    pwm_1_output = !vcselFault.read();

    // write once
    queue.call(&write_once);

    // timeout for dot
    dot_timeout.attach(&dot_watchdog,.05);
    // timout for app
    app_timeout.detach();
    app_timeout.attach(&app_watchdog,1);
}

void flood_falling_edge()
{
    flood_timer_number = flood_timer.read_us();

    if (!stacked) {
        emitter_status_dot = dot_on;
    }
    // indicate status dot
    pwm_0_output = emitter_status_dot;
    // indicate VCSEL fault if it exists
    pwm_1_output = !vcselFault.read();
    // timeout for app exit
    //timeout.attach(&write_off,.5);
    // write once
    queue.call(&write_once);

    // timeout for flood
    flood_timeout.attach(&flood_watchdog,.05);
    // timout for app
    app_timeout.detach();
    app_timeout.attach(&app_watchdog,1);
}


void dot_check()
{
    dot_timeout.detach();
    dot_timer.reset();

    dot_counter ++;
    if(dot_counter > app_counts_required) {
        dot_on = true;
        in_app = true;
    } else {
        dot_on = false;
    }
    stacked = strobe0.read();
    if(stacked) {
        stacked_counter++;
    } else {
        stacked_counter = 0;
        flood_counter = 0;
        flood_on = false;
    }
    if(!in_app) {
        if (stacked_counter > app_counts_required) {
            in_app = true;
        }
    }
}


void flood_check()
{
    flood_timeout.detach();
    flood_timer.reset();

    flood_counter ++;
    if(flood_counter > app_counts_required) {
        flood_on = true;
        in_app = true;
    } else {
        flood_on = false;
    }
    stacked = strobe1.read();
    if(stacked) {
        stacked_counter++;
    } else {
        stacked_counter = 0;
        dot_counter = 0;
        dot_on = false;
    }
    if(!in_app) {
        if (stacked_counter > app_counts_required) {
            in_app = true;
        }
    }
}

void test_function()
{

}

void morse_callback(int val)
{
    red = !val;
}

//     TODOS    //
//  DONE    P0  Get illumination working
//  P0  Get OV580 I2C to look correct. Suspect open drain culprit
//  DONE    P0  Ensure that current implementation meets the needs of data collection
//  DONE    P0  Get in app working
//  DONE    P0  Get watchdog time working
//  DONE    P0      Check watchdog for working on dot and flood
//  P1  Bluetooth OTA updates
//  P2  Get writing working
//  P2  Get reading working
//

// main() runs in its own thread in the OS
int main()
{
    Thread eventThread(osPriorityHigh);
    eventThread.start(callback(&queue, &EventQueue::dispatch_forever));

     unsigned int index = 0;
     SEGGER_RTT_printf(index, "%s\n", "main, Hello NRF58-DK\n");
 
    ov580_I2C.frequency(NRF_I2CSlave_frequency);  
    ov580_I2C.address(NRF_I2CSlave_addr);

     for (int i=0; i<MY_BUF_SIZE; i++) {
        *(i2c_tx_buff_ptr+i) = 0xaa;
    }
    for (int i=0; i<MY_BUF_SIZE; i++) {
        *(i2c_rx_buff_ptr+i) = 0x55;
    }
    
    NRF_TWIS0->ADDRESS[1] = NRF_I2CSlave_addr;
    NRF_TWIS0->ADDRESS[0] = NRF_I2CSlave_addr;
    NRF_TWIS0->TXD.PTR = (uint32_t)i2c_tx_buff_ptr;
    NRF_TWIS0->TXD.MAXCNT = MY_BUF_SIZE;
    NRF_TWIS0->RXD.PTR = (uint32_t)i2c_rx_buff_ptr;
    NRF_TWIS0->RXD.MAXCNT = MY_BUF_SIZE;   
   
    NRF_TWIS1->ADDRESS[1] = NRF_I2CSlave_addr;
    NRF_TWIS1->ADDRESS[0] = NRF_I2CSlave_addr;   
    NRF_TWIS1->TXD.PTR = (uint32_t)i2c_tx_buff_ptr;
    NRF_TWIS1->TXD.MAXCNT = MY_BUF_SIZE;
    NRF_TWIS1->RXD.PTR = (uint32_t)i2c_rx_buff_ptr;
    NRF_TWIS1->RXD.MAXCNT = MY_BUF_SIZE;
    
    SEGGER_RTT_printf(index, "CONFIG0: %d\n", NRF_TWIS0->CONFIG);
    SEGGER_RTT_printf(index, "CONFIG1: %d\n", NRF_TWIS1->CONFIG);
    NRF_TWIS0->ENABLE = 1;
    NRF_TWIS1->ENABLE = 1;
    NRF_TWIS0->TASKS_PREPARERX = 1;
    NRF_TWIS0->TASKS_PREPARETX = 1;
    NRF_TWIS1->TASKS_PREPARERX = 1;
    NRF_TWIS1->TASKS_PREPARETX = 1;
    
    NRF_TWIS0->TASKS_RESUME = 1;
    NRF_TWIS1->TASKS_RESUME = 1;
   
//    ov580_I2C.stop();
    
    red = 1;
    green = 1;
    blue = 1; 
    in_app = true;         // TODO(Jasoncha) check with Clayton
    int i2c_return = -1;
     
    // set interrupts
    int_strobe_dot.rise(&dot_check);
    int_strobe_flood.rise(&flood_check);
    int_strobe_dot.fall(&dot_falling_edge);
    int_strobe_flood.fall(&flood_falling_edge);

    dot_timer.start();
    flood_timer.start();
    
   #if 0
   MorseGenerator morse = MorseGenerator(morse_callback);
   morse.transmit(version_number);
   #endif
 

    while(!in_app) {
        wait(.1);
    }
   
    silego = 1;
 
 #if 0   //TODO(jasoncha) check with Clayton
    // write safety
    flood_I2C.write(LM36011_addr,lmSafety,2,false);
    dot_I2C.write(LM36011_addr,lmSafety,2,false);
 
    // write torch
    flood_I2C.write(LM36011_addr,torchBrightness_both,2,false);
    dot_I2C.write(LM36011_addr,torchBrightness_both,2,false);

    // write brightness
    flood_I2C.write(LM36011_addr,flashBrightness_flood,2,false);
    dot_I2C.write(LM36011_addr,flashBrightness_dot,2,false);
#endif

    blue = 0;
    SEGGER_RTT_printf(index, "%s\n", "Before loop");
    
    while (true) {
    // Handle I2C slave receive from OV580 master transmit
  //      SEGGER_RTT_printf(index, "%s\n","ov580_I2C.receive()");
        i2c_recv = ov580_I2C.receive();
        if (i2c_recv != 0) {
            SEGGER_RTT_printf(index, "%d\n",i2c_recv);
        }
        switch(i2c_recv) {
            case I2CSlave::ReadAddressed:
            SEGGER_RTT_printf(index, "%s\n", "ReadAddressed");
            red = 0;
            blue = 1;
//          ov580_I2C.write(i2c_tx_buff, strlen(i2c_tx_buff) + 1);
            i2c_return = ov580_I2C.write(&i2c_tx_data, 1);
            break;
            
            case I2CSlave::WriteGeneral:
            SEGGER_RTT_printf(index, "%s\n", "WriteGeneral");
            green = 0;
            blue = 1;
//           ov580_I2C.read(i2c_rx_buff, MY_BUF_SIZE);
            i2c_return = ov580_I2C.read(&i2c_rx_data, 1);
            break;
            
            case I2CSlave::WriteAddressed:
            SEGGER_RTT_printf(index, "%s\n", "WriteAddressed");
            green = 0;
            blue = 1;
//           ov580_I2C.read(i2c_rx_buff, MY_BUF_SIZE);
            i2c_return = ov580_I2C.read(&i2c_rx_data, 1);
            break;
            
            case I2CSlave::NoData:
  //          blue = 1;
            ov580_I2C.stop();
            break;
        }
    
#if 0
    // Handle flood and dot illuminators
        if(dot_timer_number > 700 && dot_timer_number < 1499) {
            dot_current_setting = dot_one_ms;

        } else if(dot_timer_number > 1500 && dot_timer_number < 2499) {
            dot_current_setting = dot_two_ms;

        } else if(dot_timer_number > 2500 && dot_timer_number < 3499) {
            dot_current_setting = dot_three_ms;

        } else if(dot_timer_number > 3500 && dot_timer_number < 4499) {
            dot_current_setting = dot_four_ms;

        } else if(dot_timer_number > 4500) {
            dot_current_setting = dot_five_ms;

        } else {
            dot_current_setting = dot_zero_ms;
        }

        level_dot_max_dec = uint32_t(dot_current_setting/divisor);
        level_dot_max = (((level_dot_max_dec / 16) << 4) & 0xf0) |
                        ((level_dot_max_dec % 16) & 0x0f);

        flashBrightness_dot[1] = level_dot_max;

        dot_I2C.write(LM36011_addr,flashBrightness_dot,2,false);
        wait(.01);

        if(flood_timer_number > 700 && flood_timer_number < 1499) {
            flood_current_setting = flood_one_ms;

        } else if(flood_timer_number > 1500 && flood_timer_number < 2499) {
            flood_current_setting = flood_two_ms;

        } else if(flood_timer_number > 2500 && flood_timer_number < 3499) {
            flood_current_setting = flood_three_ms;

        } else if(flood_timer_number > 3500 && flood_timer_number < 4499) {
            flood_current_setting = flood_four_ms;

        } else if(flood_timer_number > 4500) {
            flood_current_setting = flood_five_ms;

        } else {
            flood_current_setting = flood_zero_ms;
        }

        level_flood_max_dec = uint32_t(flood_current_setting/divisor);
        level_flood_max = (((level_flood_max_dec / 16) << 4) & 0xf0) |
                         ((level_flood_max_dec % 16) & 0x0f);


        flashBrightness_flood[1] = level_flood_max;

        flood_I2C.write(LM36011_addr,flashBrightness_flood,2,false);

        wait(.01);
             
        silego_check_status();
#endif
        
        
    }
}