/** * @fn void interrupt ISR_handle(void) * @brief * * @param none * @return nothing */ void interrupt ISR_handle(void) { uint8_t ui8_slave_state = 0; uint8_t ui8_i2c_value = 0; if(SSPIF == 1) { SSPIF = 0; // Reset IRQ flag i2c_slave_state(&ui8_slave_state); if((ui8_slave_state == 1) || (ui8_slave_state == 3)) { i2c_slave_read(); // Read SSPBUF to clear BF bit but don't care about returned value gui8_recv_byte_idx = 0; gui8_frame_recv_size = 0; } else if(ui8_slave_state == 2) { ui8_i2c_value = i2c_slave_read(); // Read SSPBUF to clear BF bit and read data from master fifo_put(ui8_i2c_value); // copy frame size byte if(gui8_recv_byte_idx == 1) { gui8_frame_recv_size = ui8_i2c_value - 1; } /* else nothing to do */ // indicate that is the last byte received if((gui8_frame_recv_size == gui8_recv_byte_idx) && (gui8_recv_byte_idx != 0)) { gui8_token ++; // increase the number of frames received } /* else nothing to do */ gui8_recv_byte_idx ++; } /* else nothing to do */ CKP = 1; } /* else nothing to do */ }
void clear_fault(uint8_t slave_addr) { uint8_t debug; //disable if (slave_addr == CHRGR_ADDR) { i2c_slave_command(USBA_ADDR, 0x10, 0x00); // clear any existing fault } else if (slave_addr == USBA_ADDR) { //TODO add fault handling from PORTB below USBA_EN_SetLow(); for(debug = 0; debug < 100; debug++) __delay_ms(10); USBA_EN_SetHigh(); __delay_ms(20); usb_port_init(USBA_ADDR); } else if (slave_addr == USBB_ADDR) { i2c_slave_command(USBB_ADDR, 0x10, 0x00); //try manually clearing putstring0("clear fault USBB0 - REG10: "); puthexbyte0(i2c_slave_read(USBB_ADDR, 0x10)); terpri0(); // DEBUG // putstring0("clear fault USBB0 - REG17: "); puthexbyte0(i2c_slave_read(USBB_ADDR, 0x17)); terpri0(); // DEBUG - verified - auto-retry is enabled // i2c_slave_command(USBB_ADDR, 0x17, 0xF4); // disable port power i2c_slave_command(USBB_ADDR, 0x15, 0x10); // discharge vbus, disable port power i2c_slave_command(USBB_ADDR, 0x10, 0x00); // clear any existing fault for(debug = 0; debug < 100; debug++) __delay_ms(10); // usb_portb_regs.REG10 = i2c_slave_read(USBB_ADDR, 0x10); //DEBUG // putstring0("1USBB REG10: "); puthexbyte0(usb_portb_regs.REG10); terpri0(); // i2c_slave_command(USBB_ADDR, 0x17, 0xF6); i2c_slave_command(USBB_ADDR, 0x15, 0x00); for(debug = 0; debug < 100; debug++) __delay_ms(10); i2c_slave_command(USBB_ADDR, 0x10, 0x00); //try manually clearing // if the I2C reset doesn't clear it, cut power and reinitialize // usb_portb_regs.REG10 = i2c_slave_read(USBB_ADDR, 0x10); if ( usb_portb_regs.REG10 != 0x00) { USBB_EN_SetLow(); for(debug = 0; debug < 100; debug++) __delay_ms(10); USBB_EN_SetHigh(); __delay_ms(20); // usb_port_init(USBB_ADDR); //DEBUG putstring0("Clear Fault USBB1 REG10: "); puthexbyte0(i2c_slave_read(USBB_ADDR, 0x10)); terpri0(); //// putstring0("clear fault USBB1 - REG17: "); puthexbyte0(i2c_slave_read(USBB_ADDR, 0x17)); terpri0(); // DEBUG } } return; }
/** Prototype: TODO fill this in Input: Output: none Description: Usage: charger_init(); */ void usb_port_init(uint8_t addr) { // send a dummy read command to wake up the chip before doing anyhting. wait 3ms i2c_slave_read(addr, 0x00); //clear the junk byte __delay_ms(3); //TODO reset all registers then wait a few ms // TODO use GUI to go through and set all registers to what it's doing // ***Config registers // REG15 discharge VBUS and reset charge ration count i2c_slave_command(addr, 0x15, 0x13); // REG15 The ALERT# pin will be asserted if an error condition or indicator event is detected, The ALERT# pin will not be asserted on LOW_CUR or TREG, disable discharge and close VBUS switch, disable rationing, set ration to ignore i2c_slave_command(addr, 0x15, 0x03); // REG16 (default)The timeout and idle reset functionality is disabled for I2C, Emulation timeout is enabled during the DCE Cycle, restart DCE Cycle if no profile accepted, keep last DPDM setting once device starts drawing >Ichg/profile accepted, i2c_slave_command(addr, 0x16, 0x8C); // REG17 set pin ignore, M1=0,M2=EM_EN=1 (BC1.2 DCP), S0=1 (detection enabled), auto-retry on fault/error condition i2c_slave_command(addr, 0x17, 0xF6); // REG18 (default) set discharge time to 200ms, set attach/removal detection threshold to 800uA/700uA i2c_slave_command(addr, 0x18, 0x46); // REG25 disable highspeed data switch in all cases (it's not connected to anything) i2c_slave_command(addr, 0x25, 0x10); // *** End Config registers // REG19 set current limit to 2.5A (matches ILIM set by external resistor) i2c_slave_command(addr, 0x19, 0x03); //REG1E (default) set IBUS_CHG (min acceptable current when cycling DCE profiles) to 39mA i2c_slave_command(addr, 0x1E, 0x04); // REG1A-1B set max current ration to pack capacity BATT_CAP TODO adjust this smartly between ports based on how much has been drawn i2c_slave_command(addr, 0x1A, 0x0F); //REG20 disable DCP during DCE cycling i2c_slave_command(addr, 0x20, 0x16); i2c_slave_command(addr, 0x10, 0x00); // clear any existing error flags return; }
int ds1307_read_ram(i2c_dev_t *dev, uint8_t offset, uint8_t *buf, uint8_t len) { if (offset + len > RAM_SIZE) return -EINVAL; uint8_t reg = RAM_REG + offset; return i2c_slave_read(dev->bus, dev->addr, ®, buf, len); }
/** Prototype: void slave_check_fault(uint8_t addr) Input: slave_addr: I2C address of slave Output: none Description: poll the I2C slave to see if any faults are occurring. if so, report Usage: slave_check_fault(USBA_ADDR); */ void slave_check_fault(uint8_t slave_addr) { //putstring0("slave_check_fault"); if (slave_addr == CHRGR_ADDR) { usb_chrgr_regs.REG09 = i2c_slave_read(CHRGR_ADDR, 0x09); // clear any existing fault usb_chrgr_regs.REG09 = i2c_slave_read(CHRGR_ADDR, 0x09); if (usb_chrgr_regs.REG09 != 0x00) // check for errors { print_fault(CHRGR_ADDR, 0x09, usb_chrgr_regs.REG09); } } else if (slave_addr == USBA_ADDR) { i2c_slave_command(USBA_ADDR, 0x10, 0x00); // clear any existing fault // usb_porta_regs.REG10 = i2c_slave_read(USBA_ADDR, 0x10); // __delay_ms(5); // give time for potential reset condition to occur // if (usb_porta_regs.REG10 & 0x20) // if device has been reset, reinitialize // usb_port_init(USBA_ADDR); usb_porta_regs.REG10 = i2c_slave_read(USBA_ADDR, 0x10); if (usb_porta_regs.REG10 != 0x00) // check for errors { print_fault(USBA_ADDR, 0x10, usb_porta_regs.REG10); clear_fault(USBA_ADDR); } } else if (slave_addr == USBB_ADDR) { i2c_slave_command(USBB_ADDR, 0x10, 0x00); // clear any existing fault // usb_portb_regs.REG10 = i2c_slave_read(USBB_ADDR, 0x10); // __delay_ms(5); // give time for potential reset condition to occur // if (usb_portb_regs.REG10 & 0x20) // if device has been reset, reinitialize // usb_port_init(USBB_ADDR); usb_portb_regs.REG10 = i2c_slave_read(USBB_ADDR, 0x10); if (usb_portb_regs.REG10 != 0x00) // check for errors { print_fault(USBB_ADDR, 0x10, usb_portb_regs.REG10); clear_fault(USBB_ADDR); } } return; }
static void handler (void) { // Disable interrupt temp extint_disable (extint1); irq_clear (AT91C_ID_IRQ1); uint8_t addr; uint8_t buffer[2]; i2c_ret_t ret; DELAY_US (4); //pio_output_toggle (LED1_PIO); ret = i2c_slave_read (i2c_slave1, buffer, sizeof (buffer), 10000); addr = buffer[0] - ARRAY_OFFSET; if (addr >= sizeof (comms_data)) addr = 0; if (ret == 1) { // Have not received photo line command. if (buffer[0] != CD_PHOTO_LINE) ret = i2c_slave_write (i2c_slave1, comms_data[addr], 130, 1000); // Return data requested. else { // check if photo ready. if (comms_data[CD_PHOTO_READY-ARRAY_OFFSET]) { ret = i2c_slave_write (i2c_slave1, comms_data[CD_PHOTO_NEXT_LINE-ARRAY_OFFSET], 130, 1000); if (ret > 0) { ret++; *comms_data[CD_FAULT - ARRAY_OFFSET] = ret; comms_data[CD_PHOTO_NEXT_LINE-ARRAY_OFFSET] += ret; if ((comms_data[CD_PHOTO_NEXT_LINE-ARRAY_OFFSET] - image) == image_size) { // We have sent the entire picture comms_data[CD_PHOTO_NEXT_LINE-ARRAY_OFFSET] = image; comms_data[CD_PHOTO_READY-ARRAY_OFFSET] = 0; } } } } } if (ret == 2) { if (buffer[0] == COMMS_COMMAND) next_command = buffer[1]; } extint_enable (extint1); }
void ds1307_get_time(i2c_dev_t *dev, struct tm *time) { uint8_t buf[7]; uint8_t reg = TIME_REG; i2c_slave_read(dev->bus, dev->addr, ®, buf, 7); time->tm_sec = bcd2dec(buf[0] & SECONDS_MASK); time->tm_min = bcd2dec(buf[1]); if (buf[2] & HOUR12_BIT) { // RTC in 12-hour mode time->tm_hour = bcd2dec(buf[2] & HOUR12_MASK) - 1; if (buf[2] & PM_BIT) time->tm_hour += 12; } else time->tm_hour = bcd2dec(buf[2] & HOUR24_MASK); time->tm_wday = bcd2dec(buf[3]) - 1; time->tm_mday = bcd2dec(buf[4]); time->tm_mon = bcd2dec(buf[5]) - 1; time->tm_year = bcd2dec(buf[6]) + 2000; }
static uint8_t read_register(i2c_dev_t *dev, uint8_t reg) { uint8_t val; i2c_slave_read(dev->bus, dev->addr, ®, &val, 1); return val; }
int I2CSlave::read(char *data, int length) { return i2c_slave_read(&_i2c, data, length) != length; }
/**************************************************************************** * * Main application * ****************************************************************************/ void main(void) { // adc_result_t vbatt; // raw ADC of battery voltage // adc_result_t vbus; // raw ADC of charger input voltage uint8_t soc_leds; // result of raw ADC to 5 SOC LED conversion uint8_t c; // dbg0, dbg1, // initialize the device SYSTEM_Initializer(); CE_N_SetLow(); // enable the input charger USBA_EN_SetHigh(); // enable usb porta M1_A_SetLow(); // don't care since using pin_ignore/I2C only mode M2_A_SetHigh(); // don't care since using pin_ignore/I2C only mode EM_EN_A_SetHigh(); // don't care since using pin_ignore/I2C only mode USBB_EN_SetHigh(); // enable usb portb M1_B_SetLow(); // don't care since using pin_ignore/I2C only mode M2_B_SetHigh(); // don't care since using pin_ignore/I2C only mode EM_EN_B_SetHigh(); // don't care since using pin_ignore/I2C only mode otg_mode_flag = 0; // initialise variables BTN0_dbstate = 0; // initial pushbutton state = released BTN0_change = 0; // clear pushbutton change flag (no change) BTN1_dbstate = 0; // initial pushbutton state = released BTN1_change = 0; // clear pushbutton change flag (no change) ADC_read_flag = 0; // //ADC_channel = 0; print_start_msg(); __delay_ms(10); // DEBUG charger_init(); __delay_ms(10); //DS: Upon power-up, the UCS1002 will not respond to any SMBus communications for 5.5 ms usb_port_init(USBA_ADDR); // setup the USB smart output chips __delay_ms(10); // DEBUG usb_port_init(USBB_ADDR); // setup the USB smart output chips //enable interrupts - TODO should this wait unitl after i2c init routines? INTCONbits.IOCIF = 0; IOCBF1 = 0; IOCBF2 = 0; IOCBF3 = 0; IOCBF4 = 0; INTCONbits.IOCIE = 1; TMR0_StartTimer(); TMR1_StartTimer(); TMR2_StartTimer(); INTERRUPT_PeripheralInterruptEnable(); INTERRUPT_GlobalInterruptEnable(); // enable global interrupts /** * CORE APPLICATION */ while (1) { // Add your application code //***DEBUG***// if (EUSART_IsDataReady() == 1) // check for input { c = EUSART_GetByte(); // reading RCREG clear RCIF select_status_report(c); } if (A_DET_A_N_GetValue() == 0) FLASHLIGHT_SetHigh(); //***DEBUG***// // check for self-attached cable if (SELF_DETECT_GetValue() == 1) { USBA_EN_SetLow(); putstring0("Self Detect, USBA disabled"); // DEBUG } else USBA_EN_SetHigh(); //grab battery level, input voltage, update SOC byte if (ADC_read_flag == 1) { ADC_read_flag = 0; vbatt = (ADC_GetConversion(channel_AN1) << 1); // input voltage divided by 2 - multiply it back __delay_ms(1); // provide switching time // vbus = (ADC_GetConversion(channel_AN2) << 1); // TODO figure out what to do with this } soc_leds = calc_soc(vbatt); // check for debounced button press // if (BTN0_change && !BTN0_dbstate) // if button state changed and pressed (low) if (DBG_SPARE_change && DBG_SPARE_dbstate) // if button state changed and pressed (high) { FLASHLIGHT_Toggle(); // turn flashlight off and on // BTN0_change = 0; // clear button change flag DBG_SPARE_change = 0; // clear button change flag } // if (BTN1_change && !BTN1_dbstate) // if button state changed and pressed (low) // { // soc_cntr_start_flag = 1; soc_update(soc_leds); // display SOC animation // BTN1_change = 0; // clear button change flag // } // if (soc_cntr_done_flag == 1) // let the SOC display stand for 5s // { // dbg1 += 1; // soc_cntr_start_flag = 0; // soc_cntr_done_flag = 0; // soc_update(dbg1); //// soc_update(CLR_SOC); // } // TODO update more charger regs, react slave_check_fault(CHRGR_ADDR); if (otg_mode_flag == 1) i2c_slave_command(CHRGR_ADDR, 0x01, 0x6B); //REG01 reset watchdog, enable OTG only else i2c_slave_command(CHRGR_ADDR, 0x01, 0x5B); //REG01 reset watchdog, enable charger only // TODO update more usba regs, react slave_check_fault(USBA_ADDR); usb_porta_regs.REG00 = i2c_slave_read(USBA_ADDR, 0x00); //update the current reading // TODO update more usbb regs, react slave_check_fault(USBB_ADDR); usb_portb_regs.REG00 = i2c_slave_read(USBB_ADDR, 0x00); //update the current reading //debug // for (dbg0 = 0; dbg0 < 255; dbg0++); // { // __delay_ms(100); // } // soc_update(dbg1); // dbg1 += 1; // if (dbg1 == 0x1F) // dbg1 = 0; // if (debug_rprt_flag == 1) // { // debug_rprt_flag = 0; // FLASHLIGHT_Toggle(); // // } } }
void try_profile(uint8_t slave_addr, uint8_t profile, uint8_t dce, uint8_t* draw_best_ptr, uint8_t* best_profile_ptr, uint8_t* best_dce_ptr) { uint8_t draw_now, cnt; // Try cycling each of the DCE profiles on one at a time TODO is there a better way to do this? //REG21 enable single legacy profiles during DCE cycling. skip if null (non DCE profile attempts) if (dce) i2c_slave_command(slave_addr, 0x21, dce); i2c_slave_command(slave_addr, 0x17, (profile & ~(1 << 1))); //disable port power putstring0("Config REG17 0 (hex): "); puthexbyte0(i2c_slave_read(slave_addr, 0x17)); terpri0(); soc_update(0x00); // i2c_slave_command(slave_addr, 0x15, 0x10); // discharge vbus, disable port power for (cnt = 0; cnt < PRFL_WAIT_MS/10; cnt++) //TODO see how much this can be reduced __delay_ms(10); // i2c_slave_command(slave_addr, 0x15, 0x00); // i2c_slave_command(slave_addr, 0x17, profile); //enable port power putstring0("Config REG17 1 (hex): "); puthexbyte0(i2c_slave_read(slave_addr, 0x17)); terpri0(); soc_update(0xFF); for (cnt = 0; cnt < PRFL_WAIT_MS/10; cnt++) //wait for profile to be applied and go into effect on device __delay_ms(10); draw_now = i2c_slave_read(slave_addr, 0x00); //update the current reading if (draw_now > *draw_best_ptr) { *best_dce_ptr = dce; *best_profile_ptr = profile; *draw_best_ptr = draw_now; } //debug if (slave_addr == USBA_ADDR) { putstring0("USBA try profile port current: "); print_current(draw_now); print_status(USBA_ADDR, 0x12, i2c_slave_read(USBA_ADDR, 0x12)); terpri0(); // show applied profile 1 BC 1.2 print_status(USBA_ADDR, 0x13, i2c_slave_read(USBA_ADDR, 0x13)); terpri0(); // show applied profile 2 legacy putstring0("Config REG17 (hex): "); puthexbyte0(i2c_slave_read(USBA_ADDR, 0x17)); terpri0(); putstring0("Applied emulation REG30 (hex): "); puthexbyte0(i2c_slave_read(USBA_ADDR, 0x30)); terpri0(); terpri0(); // IOCBF3 = 0; } if (slave_addr == USBB_ADDR) { putstring0("USBB try profile port current: "); print_current(draw_now); print_status(USBB_ADDR, 0x12, i2c_slave_read(USBB_ADDR, 0x12)); terpri0(); print_status(USBB_ADDR, 0x13, i2c_slave_read(USBB_ADDR, 0x13)); terpri0(); putstring0("Config REG17 (hex): "); puthexbyte0(i2c_slave_read(USBB_ADDR, 0x17)); terpri0(); putstring0("Applied emulation REG30 (hex): "); puthexbyte0(i2c_slave_read(USBB_ADDR, 0x30)); terpri0(); terpri0(); // IOCBF4 = 0; } return; }
void do_best_profile(uint8_t slave_addr) //TODO should we test if current draw already > some threshold (e.g. 0.8A) then skip this? { uint8_t draw_best, best_profile, best_dce, cnt; //draw_now // uint8_t* draw_now_ptr, draw_best_ptr, best_profile_ptr, best_dce_ptr; // // draw_now_ptr = &draw_now; // draw_best_ptr = &draw_best; // best_profile_ptr = &best_profile; // best_dce_ptr = &best_dce_ptr; // INTERRUPT_GlobalInterruptDisable(); INTCONbits.IOCIE = 0; putstring0("do best profile"); terpri0(); for (cnt = 0; cnt < PRFL_WAIT_MS/10; cnt++) //debug - the a_det is very sensitive, stall while connector is finished inserting __delay_ms(10); //REG21 disable all legacy profiles, enable one by one during DCE cycling i2c_slave_command(slave_addr, 0x21, 0x7F); // draw_now = i2c_slave_read(slave_addr, 0x00); //update the current reading draw_best = i2c_slave_read(slave_addr, 0x00); //update the current reading // Try the different emulation profiles, make note of the best putstring0("trying SDP"); terpri0(); try_profile(slave_addr, SDP, 0, &draw_best, &best_profile, &best_dce); putstring0("trying CDP"); terpri0(); try_profile(slave_addr, CDP, 0, &draw_best, &best_profile, &best_dce); putstring0("trying DCP"); terpri0(); try_profile(slave_addr, DCP, 0, &draw_best, &best_profile, &best_dce); putstring0("trying DCE1"); terpri0(); try_profile(slave_addr, DCE, DCE_P1, &draw_best, &best_profile, &best_dce); putstring0("trying DCE2"); terpri0(); try_profile(slave_addr, DCE, DCE_P2, &draw_best, &best_profile, &best_dce); putstring0("trying DCE3"); terpri0(); try_profile(slave_addr, DCE, DCE_P3, &draw_best, &best_profile, &best_dce); putstring0("trying DCE4"); terpri0(); try_profile(slave_addr, DCE, DCE_P4, &draw_best, &best_profile, &best_dce); putstring0("trying DCE5"); terpri0(); try_profile(slave_addr, DCE, DCE_P5, &draw_best, &best_profile, &best_dce); putstring0("trying DCE6"); terpri0(); try_profile(slave_addr, DCE, DCE_P6, &draw_best, &best_profile, &best_dce); putstring0("trying DCE7"); terpri0(); try_profile(slave_addr, DCE, DCE_P7, &draw_best, &best_profile, &best_dce); // apply the best one putstring0("Best DCE (hex): "); puthexbyte0(best_dce); terpri0(); putstring0("Best Profile (hex): "); puthexbyte0(best_profile); terpri0(); if (best_profile == DCE) // only sent if legacy is best i2c_slave_command(slave_addr, 0x21, best_dce); i2c_slave_command(slave_addr, 0x17, (best_profile & ~(1 << 1))); //disable port power // i2c_slave_command(slave_addr, 0x15, 0x10); // discharge vbus, disable port power for (cnt = 0; cnt < PRFL_WAIT_MS/10; cnt++) //TODO see how much this can be reduced __delay_ms(10); i2c_slave_command(slave_addr, 0x17, best_profile); //enable port power // i2c_slave_command(slave_addr, 0x15, 0x00); // // INTERRUPT_GlobalInterruptEnable(); terpri0(); terpri0(); print_selections_msg(); INTCONbits.IOCIE = 1; return; }