2018-03-11 17:51:53 +01:00
/* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation , either version 3 of the License , or
* ( at your option ) any later version .
*
* This program 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 General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program . If not , see < http : //www.gnu.org/licenses/>.
*
*/
/** BusVoodoo I²C mode (code)
* @ file busvoodoo_i2c . c
* @ author King Kévin < kingkevin @ cuvoodoo . info >
* @ date 2018
* @ note peripherals used : I2C @ ref busvoodoo_i2c
*/
/* standard libraries */
# include <stdint.h> // standard integer types
# include <stdlib.h> // standard utilities
# include <string.h> // string utilities
/* STM32 (including CM3) libraries */
2018-03-20 09:38:18 +01:00
# include <libopencm3/stm32/i2c.h> // I2C library
2018-03-11 17:51:53 +01:00
/* own libraries */
# include "global.h" // board definitions
# include "print.h" // printing utilities
# include "menu.h" // menu definitions
2018-03-20 09:38:18 +01:00
# include "i2c_master.h" // I2C utilities
2018-03-11 17:51:53 +01:00
# include "busvoodoo_global.h" // BusVoodoo definitions
# include "busvoodoo_oled.h" // OLED utilities
# include "busvoodoo_i2c.h" // own definitions
2018-03-20 09:38:18 +01:00
/** @defgroup busvoodoo_i2c I2C peripheral to communicate with I2C devices
* @ {
*/
# define BUSVOODOO_I2C I2C2 /**< I2C peripheral */
/** @} */
2018-03-11 17:51:53 +01:00
/** mode setup stage */
static enum busvoodoo_i2c_setting_t {
BUSVOODOO_I2C_SETTING_NONE ,
BUSVOODOO_I2C_SETTING_SPEED ,
BUSVOODOO_I2C_SETTING_ADDRESSBITS ,
BUSVOODOO_I2C_SETTING_PULLUP ,
BUSVOODOO_I2C_SETTING_DONE ,
2018-03-21 23:20:39 +01:00
} busvoodoo_i2c_setting = BUSVOODOO_I2C_SETTING_NONE ; /**< current mode setup stage */
2018-03-11 17:51:53 +01:00
/** I2C speed (in kHz) */
uint16_t busvoodoo_i2c_speed = 100 ;
/** I2C address bits (7 or 10) */
uint8_t busvoodoo_i2c_addressbits = 7 ;
/** if embedded or external pull-up resistors are use */
bool busvoodoo_i2c_embedded_pullup = true ;
/** setup I2C mode
* @ param [ out ] prefix terminal prompt prefix
* @ param [ in ] line terminal prompt line to configure mode
* @ return if setup is complete
*/
static bool busvoodoo_i2c_setup ( char * * prefix , const char * line )
{
bool complete = false ; // is the setup complete
if ( NULL = = line ) { // first call
busvoodoo_i2c_setting = BUSVOODOO_I2C_SETTING_NONE ; // re-start configuration
}
switch ( busvoodoo_i2c_setting ) {
case BUSVOODOO_I2C_SETTING_NONE :
2018-03-15 18:55:31 +01:00
snprintf ( busvoodoo_global_string , LENGTH ( busvoodoo_global_string ) , " speed in kHz (1-400) [%u] " , busvoodoo_i2c_speed ) ;
* prefix = busvoodoo_global_string ; // ask for speed
2018-03-11 17:51:53 +01:00
busvoodoo_i2c_setting = BUSVOODOO_I2C_SETTING_SPEED ;
break ;
case BUSVOODOO_I2C_SETTING_SPEED :
if ( NULL = = line | | 0 = = strlen ( line ) ) { // use default setting
busvoodoo_i2c_setting = BUSVOODOO_I2C_SETTING_ADDRESSBITS ; // go to next setting
} else { // setting provided
uint32_t speed = atoi ( line ) ; // parse setting
if ( speed > 0 & & speed < = 400 ) { // check setting
busvoodoo_i2c_speed = speed ; // remember setting
busvoodoo_i2c_setting = BUSVOODOO_I2C_SETTING_ADDRESSBITS ; // go to next setting
}
}
if ( BUSVOODOO_I2C_SETTING_ADDRESSBITS = = busvoodoo_i2c_setting ) { // if next setting
2018-03-15 18:55:31 +01:00
snprintf ( busvoodoo_global_string , LENGTH ( busvoodoo_global_string ) , " address size in bits (7,10) [%u] " , busvoodoo_i2c_addressbits ) ; // prepare next setting
* prefix = busvoodoo_global_string ; // display next setting
2018-03-11 17:51:53 +01:00
}
break ;
case BUSVOODOO_I2C_SETTING_ADDRESSBITS :
if ( NULL = = line | | 0 = = strlen ( line ) ) { // use default setting
busvoodoo_i2c_setting = BUSVOODOO_I2C_SETTING_PULLUP ; // go to next setting
} else { // setting provided
uint8_t addressbits = atoi ( line ) ; // parse setting
if ( 7 = = addressbits | | 10 = = addressbits ) { // check setting
busvoodoo_i2c_addressbits = addressbits ; // remember setting
busvoodoo_i2c_setting = BUSVOODOO_I2C_SETTING_PULLUP ; // go to next setting
}
}
if ( BUSVOODOO_I2C_SETTING_PULLUP = = busvoodoo_i2c_setting ) { // if next setting
2018-03-20 10:46:40 +01:00
printf ( " 1) open-drain, with embedded pull-up resistors (2kO) \n " ) ;
printf ( " 2) open-drain, with external pull-up resistors \n " ) ;
2018-03-20 10:15:36 +01:00
snprintf ( busvoodoo_global_string , LENGTH ( busvoodoo_global_string ) , " drive mode (1,2) [%c] " , busvoodoo_i2c_embedded_pullup ? ' 1 ' : ' 2 ' ) ; // show drive mode
2018-03-15 18:55:31 +01:00
* prefix = busvoodoo_global_string ; // display next setting
2018-03-11 17:51:53 +01:00
}
break ;
case BUSVOODOO_I2C_SETTING_PULLUP :
if ( NULL = = line | | 0 = = strlen ( line ) ) { // use default setting
busvoodoo_i2c_setting = BUSVOODOO_I2C_SETTING_DONE ; // go to next setting
2018-03-20 10:15:36 +01:00
} else if ( 1 = = strlen ( line ) ) { // setting provided
uint8_t drive = atoi ( line ) ; // parse setting
if ( 1 = = drive | | 2 = = drive ) { // check setting
busvoodoo_i2c_embedded_pullup = ( 1 = = drive ) ; // remember setting
2018-03-11 17:51:53 +01:00
busvoodoo_i2c_setting = BUSVOODOO_I2C_SETTING_DONE ; // go to next setting
}
}
if ( BUSVOODOO_I2C_SETTING_DONE = = busvoodoo_i2c_setting ) { // we have all settings, configure I2C
2018-03-21 10:14:00 +01:00
i2c_master_setup ( BUSVOODOO_I2C , busvoodoo_i2c_speed ) ; // setup I2C
2018-03-20 10:42:59 +01:00
if ( busvoodoo_i2c_embedded_pullup ) {
busvoodoo_embedded_pullup ( true ) ; // set pull-up
2018-03-22 12:09:18 +01:00
printf ( " use LV to set pull-up voltage \n " ) ;
2018-03-20 10:42:59 +01:00
}
2018-03-11 17:51:53 +01:00
led_off ( ) ; // disable LED because there is no activity
busvoodoo_i2c_setting = BUSVOODOO_I2C_SETTING_NONE ; // restart settings next time
* prefix = " I2C " ; // display mode
busvoodoo_oled_text_left ( * prefix ) ; // set mode title on OLED display
2018-03-20 10:15:36 +01:00
const char * pinout_io [ 10 ] = { " GND " , " 5V " , " 3V3 " , " LV " , " SDA " , " SCL " , NULL , NULL } ; // HiZ mode pinout
2018-03-11 17:51:53 +01:00
for ( uint8_t i = 0 ; i < LENGTH ( pinout_io ) & & i < LENGTH ( busvoodoo_global_pinout_io ) ; i + + ) {
busvoodoo_global_pinout_io [ i ] = pinout_io [ i ] ; // set pin names
}
busvoodoo_oled_text_pinout ( pinout_io , true ) ; // set pinout on display
busvoodoo_oled_update ( ) ; // update display to show text and pinout
complete = true ; // configuration is complete
}
break ;
case BUSVOODOO_I2C_SETTING_DONE : // this case is already handled before
default : // unknown case
busvoodoo_i2c_setting = BUSVOODOO_I2C_SETTING_NONE ; // restart settings next time
complete = false ; // restart setting
break ;
}
return complete ;
}
/** exit I2C mode
*/
static void busvoodoo_i2c_exit ( void )
{
2018-03-20 09:38:18 +01:00
i2c_master_release ( BUSVOODOO_I2C ) ; // release I2C peripheral
2018-03-11 17:51:53 +01:00
busvoodoo_embedded_pullup ( false ) ; // disable embedded pull-ups
}
2018-03-21 14:15:15 +01:00
/** read from I2C */
static void busvoodoo_i2c_read ( void )
{
printf ( " read: " ) ;
2018-03-22 12:09:18 +01:00
busvoodoo_led_blue_pulse ( BUSVOODOO_LED_PULSE ) ; // pulse blue LED to show we read data
2018-03-21 14:15:15 +01:00
uint8_t data ; // to store the data read
switch ( i2c_master_read ( BUSVOODOO_I2C , & data , 1 ) ) {
case I2C_MASTER_RC_NONE : // all went fine
printf ( " 0x%02x " , data ) ; // show data
break ;
case I2C_MASTER_RC_NOT_MASTER :
printf ( " slave not selected " ) ;
break ;
case I2C_MASTER_RC_NOT_READY :
printf ( " slave not ready " ) ;
break ;
case I2C_MASTER_RC_NOT_RECEIVE :
printf ( " not in receive mode " ) ;
break ;
default :
printf ( " error " ) ;
}
printf ( " \n " ) ;
}
/** write to I2C
* @ param [ in ] data data to write
*/
static void busvoodoo_i2c_write ( uint8_t data )
{
printf ( " write 0x%02x: " , data ) ;
2018-03-22 12:09:18 +01:00
busvoodoo_led_red_pulse ( BUSVOODOO_LED_PULSE ) ; // pulse red LED to show we send data
2018-03-21 14:15:15 +01:00
switch ( i2c_master_write ( BUSVOODOO_I2C , & data , 1 ) ) {
case I2C_MASTER_RC_NONE : // all went fine
printf ( " ack " ) ;
break ;
case I2C_MASTER_RC_NAK :
printf ( " nack " ) ;
break ;
case I2C_MASTER_RC_NOT_MASTER :
printf ( " slave not selected " ) ;
break ;
case I2C_MASTER_RC_NOT_READY :
printf ( " slave not ready " ) ;
break ;
case I2C_MASTER_RC_NOT_TRANSMIT :
printf ( " not in transmit mode " ) ;
break ;
default :
printf ( " error " ) ;
}
printf ( " \n " ) ;
}
/** select I2C slave
* @ param [ in ] slave slave I2C address
* @ param [ in ] write enter read ( false ) or write ( true ) mode
*/
static void busvoodoo_i2c_select ( uint16_t slave , bool write )
{
printf ( " select slave " ) ;
if ( 10 = = busvoodoo_i2c_addressbits ) {
printf ( " 0x%03x " , slave ) ;
} else {
printf ( " 0x%02x " , slave ) ;
}
printf ( " to %s: " , write ? " write " : " read " ) ;
2018-03-22 12:09:18 +01:00
busvoodoo_led_red_pulse ( BUSVOODOO_LED_PULSE ) ; // pulse red LED to show we send the slave address
2018-03-21 14:15:15 +01:00
switch ( i2c_master_select_slave ( BUSVOODOO_I2C , slave , 10 = = busvoodoo_i2c_addressbits , write ) ) {
case I2C_MASTER_RC_NONE : // all went fine
printf ( " selected " ) ;
break ;
case I2C_MASTER_RC_NAK :
printf ( " no such slave " ) ;
break ;
case I2C_MASTER_RC_NOT_MASTER :
printf ( " can't become master " ) ;
break ;
case I2C_MASTER_RC_NOT_RECEIVE :
printf ( " not in receive mode " ) ;
break ;
case I2C_MASTER_RC_NOT_TRANSMIT :
printf ( " not in transmit mode " ) ;
break ;
default :
printf ( " error " ) ;
}
printf ( " \n " ) ;
}
/** perform I2C action
* @ param [ in ] action action to perform
* @ param [ in ] repetition how many times to perform the action
* @ param [ in ] perform the action ( true ) or just check it ( false )
* @ return true if the action has been performed , false if it is malformed
*/
static bool busvoodoo_i2c_action ( const char * action , uint32_t repetition , bool perform )
{
uint32_t length = strlen ( action ) ; // remember length since it will be used a number of times
if ( NULL = = action | | 0 = = length ) { // there is nothing to do
return true ;
}
if ( 1 = = length & & ' r ' = = action [ 0 ] ) { // read data
if ( ! perform ) {
return true ;
}
for ( uint32_t i = 0 ; i < repetition ; i + + ) {
busvoodoo_i2c_read ( ) ; // read from I2C
}
} else if ( 1 = = length & & ' [ ' = = action [ 0 ] ) { // select slave
if ( ! perform ) {
return true ;
}
printf ( " send start condition: " ) ;
for ( uint32_t i = 0 ; i < repetition ; i + + ) {
2018-03-22 12:09:18 +01:00
busvoodoo_led_red_pulse ( BUSVOODOO_LED_PULSE ) ; // pulse red LED to show we send start condition
2018-03-21 14:15:15 +01:00
printf ( " %s " , I2C_MASTER_RC_NONE = = i2c_master_start ( BUSVOODOO_I2C ) ? " sent " : " error " ) ;
}
printf ( " \n " ) ;
} else if ( 1 = = length & & ' ] ' = = action [ 0 ] ) { // deselect slave
if ( ! perform ) {
return true ;
}
printf ( " send stop condition: " ) ;
for ( uint32_t i = 0 ; i < repetition ; i + + ) {
2018-03-22 12:09:18 +01:00
busvoodoo_led_red_pulse ( BUSVOODOO_LED_PULSE ) ; // pulse red LED to show we send stop condition
2018-03-21 14:15:15 +01:00
printf ( " %s " , I2C_MASTER_RC_NONE = = i2c_master_stop ( BUSVOODOO_I2C ) ? " sent " : " error " ) ;
}
printf ( " \n " ) ;
} else if ( 1 = = length & & ' u ' = = action [ 0 ] ) { // sleep us
if ( ! perform ) {
return true ;
}
printf ( " wait for %u us \n " , repetition ) ;
sleep_us ( repetition ) ; // sleep
} else if ( 1 = = length & & ' m ' = = action [ 0 ] ) { // sleep ms
if ( ! perform ) {
return true ;
}
printf ( " wait for %u ms \n " , repetition ) ;
sleep_ms ( repetition ) ; // sleep
} else if ( ' 0 ' = = action [ 0 ] ) { // send digit
if ( 1 = = length ) { // just send 0
if ( ! perform ) {
return true ;
}
for ( uint32_t i = 0 ; i < repetition ; i + + ) {
busvoodoo_i2c_write ( 0 ) ; // write to I2C
}
} else if ( ' x ' = = action [ 1 ] | | ' b ' = = action [ 1 ] ) { // send hex/binary
return busvoodoo_i2c_action ( action + 1 , repetition , perform ) ; // just retry without leading 0
} else if ( action [ 1 ] > = ' 0 ' & & action [ 1 ] < = ' 9 ' ) { // send decimal
return busvoodoo_i2c_action ( action + 1 , repetition , perform ) ; // just retry without leading 0
} else if ( ' r ' = = action [ 1 ] & & 2 = = length ) { // select slave to read
busvoodoo_i2c_select ( 0 , false ) ; // select slave 0 to read
} else if ( ' w ' = = action [ 1 ] & & 2 = = length ) { // select slave to write
busvoodoo_i2c_select ( 0 , true ) ; // select slave 0 to write
} else { // malformed action
return false ;
}
} else if ( ' x ' = = action [ 0 ] & & length > 1 ) { // send hexadecimal value
for ( uint32_t i = 1 ; i < length ; i + + ) { // check string
if ( ! ( ( action [ i ] > = ' 0 ' & & action [ i ] < = ' 9 ' ) | | ( action [ i ] > = ' a ' & & action [ i ] < = ' f ' ) | | ( action [ i ] > = ' A ' & & action [ i ] < = ' F ' ) | | ( ' r ' = = action [ i ] & & i = = length - 1 ) | | ( ' w ' = = action [ i ] & & i = = length - 1 ) ) ) { // check for hexadecimal character or r/w flag
return false ; // not an hexadecimal string
}
}
if ( ! perform ) {
return true ;
}
uint32_t value = strtol ( & action [ 1 ] , NULL , 16 ) ; // get hex value
for ( uint32_t i = 0 ; i < repetition ; i + + ) {
if ( ' r ' = = action [ length - 1 ] ) {
busvoodoo_i2c_select ( value , false ) ; // select slave to read
} else if ( ' w ' = = action [ length - 1 ] ) {
busvoodoo_i2c_select ( value , true ) ; // select slave to write
} else {
busvoodoo_i2c_write ( value ) ; // write to I2C
}
}
} else if ( ' b ' = = action [ 0 ] & & length > 1 ) { // send binary value
for ( uint32_t i = 1 ; i < length ; i + + ) { // check string
if ( ! ( ' 0 ' = = action [ i ] | | ' 1 ' = = action [ i ] | | ( ' r ' = = action [ i ] & & i = = length - 1 ) | | ( ' w ' = = action [ i ] & & i = = length - 1 ) ) ) { // check for binary character or r/w flag
return false ; // not a binary string
}
}
if ( ! perform ) {
return true ;
}
uint32_t value = strtol ( & action [ 1 ] , NULL , 2 ) ; // get binary value
for ( uint32_t i = 0 ; i < repetition ; i + + ) {
if ( ' r ' = = action [ length - 1 ] ) {
busvoodoo_i2c_select ( value , false ) ; // select slave to read
} else if ( ' w ' = = action [ length - 1 ] ) {
busvoodoo_i2c_select ( value , true ) ; // select slave to write
} else {
busvoodoo_i2c_write ( value ) ; // write to I2C
}
}
} else if ( action [ 0 ] > = ' 1 ' & & action [ 0 ] < = ' 9 ' ) { // send decimal value
for ( uint32_t i = 1 ; i < length ; i + + ) { // check string
if ( ! ( ( action [ i ] > = ' 0 ' & & action [ i ] < = ' 9 ' ) | | ( ' w ' = = action [ i ] & & i = = length - 1 ) ) ) { // check for decimal character or r/w flag
return false ; // not a decimal string
}
}
if ( ! perform ) {
return true ;
}
uint32_t value = strtol ( & action [ 0 ] , NULL , 10 ) ; // get decimal value
for ( uint32_t i = 0 ; i < repetition ; i + + ) {
if ( ' r ' = = action [ length - 1 ] ) {
busvoodoo_i2c_select ( value , false ) ; // select slave to read
} else if ( ' w ' = = action [ length - 1 ] ) {
busvoodoo_i2c_select ( value , true ) ; // select slave to write
} else {
busvoodoo_i2c_write ( value ) ; // write to I2C
}
}
} else if ( length > = 2 & & ( ' " ' = = action [ 0 ] | | ' \' ' = = action [ 0 ] ) & & ( action [ length - 1 ] = = action [ 0 ] ) ) { // send ASCII character
if ( ! perform ) {
return true ;
}
for ( uint32_t r = 0 ; r < repetition ; r + + ) {
for ( uint32_t i = 1 ; i < length - 1 ; i + + ) { // go through string
busvoodoo_i2c_write ( action [ i ] ) ; // write to I2C
}
}
} else { // malformed action
return false ;
}
return true ; // all went well
}
2018-03-11 17:51:53 +01:00
// command handlers
2018-03-21 14:15:15 +01:00
/** command to perform actions
* @ param [ in ] argument actions to perform
*/
static void busvoodoo_i2c_command_actions ( void * argument )
{
if ( NULL = = argument | | 0 = = strlen ( argument ) ) {
printf ( " available actions (separated by space or ,): \n " ) ;
printf ( " [/] \t send start/stop conditions \n " ) ;
printf ( " 0x0r \t select slave with I2C address to read \n " ) ;
printf ( " 0x0w \t select slave with I2C address to write \n " ) ;
printf ( " 0 \t write decimal value \n " ) ;
printf ( " 0x0 \t write hexadecimal value \n " ) ;
printf ( " 0b0 \t write binary value \n " ) ;
printf ( " \" a \" /'a' \t write ASCII characters \n " ) ;
printf ( " r \t read value \n " ) ;
printf ( " u/m \t wait 1 us/ms \n " ) ;
printf ( " :n \t repeat action n times \n " ) ;
return ;
}
// copy argument since it will be modified
char * copy = calloc ( strlen ( argument ) + 1 , sizeof ( char ) ) ;
if ( ! copy ) {
while ( true ) ;
}
strncpy ( copy , argument , strlen ( argument ) + 1 ) ;
// verify and perform actions
if ( ! busvoodoo_global_actions ( copy , false , & busvoodoo_i2c_action ) ) { // verify actions
printf ( " malformed action(s) \n " ) ;
} else { // action are ok
busvoodoo_global_actions ( argument , true , & busvoodoo_i2c_action ) ; // perform action
}
free ( copy ) ; // release memory
}
2018-03-11 17:51:53 +01:00
/** command to scan for slave devices
* @ param [ in ] argument no argument required
*/
static void busvoodoo_i2c_command_scan ( void * argument )
{
( void ) argument ; // we won't use the argument
2018-03-20 09:38:18 +01:00
if ( ! i2c_master_check_signals ( BUSVOODOO_I2C ) ) { // ensure SCL and SDA are high
2018-03-21 10:14:00 +01:00
printf ( " SCL or/and SDA are low. The signals need to be pulled up \n " ) ;
2018-03-11 17:51:53 +01:00
if ( busvoodoo_i2c_embedded_pullup ) {
printf ( " set pull-up voltage with LV \n " ) ;
}
led_blink ( 0.5 , 0.5 ) ; // show error on LEDs
return ; // stop here
} else {
led_off ( ) ; // switch LEDs off
}
printf ( " scanning for I2C slaves \n " ) ;
2018-03-21 10:14:00 +01:00
int16_t i2c_slaves = 0 ; // number of slaves found
2018-03-11 17:51:53 +01:00
// check for I2C slaves by going through the address space
for ( uint16_t address = 0 ; address < ( 1 < < busvoodoo_i2c_addressbits ) ; address + + ) {
2018-03-22 12:09:18 +01:00
busvoodoo_led_red_pulse ( BUSVOODOO_LED_PULSE ) ; // pulse red LED to show transmission
2018-03-21 14:15:15 +01:00
switch ( i2c_master_select_slave ( BUSVOODOO_I2C , address , 10 = = busvoodoo_i2c_addressbits , false ) ) { // try to select slave (includes start condition)
case I2C_MASTER_RC_NONE : // slave found
2018-03-22 12:09:18 +01:00
busvoodoo_led_red_pulse ( BUSVOODOO_LED_PULSE ) ; // pulse blue LED to show we found a slave
2018-03-21 14:15:15 +01:00
printf ( ( busvoodoo_i2c_addressbits > 7 ) ? " 0x%03x " : " 0x%02x " , address ) ; // display address
i2c_slaves + + ; // increase slave count
break ;
case I2C_MASTER_RC_START_STOP_IN_PROGESS : // I2C peripheral error
i2c_master_reset ( BUSVOODOO_I2C ) ; // reset the I2C peripheral since it might be stuck
printf ( " start condition failed \n " ) ; // show error to user
led_blink ( 0.5 , 0.5 ) ; // show error on LEDs
i2c_slaves = - 2 ; // remember error
break ; // stop scanning
case I2C_MASTER_RC_NOT_MASTER : // start condition failed
i2c_master_reset ( BUSVOODOO_I2C ) ; // reset the I2C peripheral since it might be stuck
printf ( " start condition failed \n " ) ; // show error to user
led_blink ( 0.5 , 0.5 ) ; // show error on LEDs
i2c_slaves = - 1 ; // remember error
break ; // stop scanning
case I2C_MASTER_RC_NAK : // slave did not respond
break ; // nothing to do
default : // unexpected error
i2c_slaves = - 1 ; // remember error
break ;
2018-03-11 17:51:53 +01:00
}
2018-03-21 14:15:15 +01:00
if ( i2c_slaves < 0 ) { // error happend
2018-03-21 10:14:00 +01:00
led_blink ( 0.5 , 0.5 ) ; // show error on LEDs
2018-03-21 14:15:15 +01:00
if ( - 1 = = i2c_slaves ) { // just end communication
i2c_master_stop ( BUSVOODOO_I2C ) ; // send stop condition
} else if ( - 2 = = i2c_slaves ) { // reset peripheral
i2c_master_reset ( BUSVOODOO_I2C ) ; // reset the I2C peripheral since it might be stuck
}
break ; // stop scan
} else {
if ( I2C_MASTER_RC_NONE ! = i2c_master_stop ( BUSVOODOO_I2C ) ) { // stop stop condition
i2c_master_reset ( BUSVOODOO_I2C ) ; // reset the I2C peripheral since it might be stuck
printf ( " stop condition failed \n " ) ; // show error to user
led_blink ( 0.5 , 0.5 ) ; // show error on LEDs
i2c_slaves = - 1 ; // remember error
break ;
}
2018-03-21 10:14:00 +01:00
}
2018-03-11 17:51:53 +01:00
}
if ( i2c_slaves > 0 ) {
printf ( " \n " ) ;
}
2018-03-21 10:14:00 +01:00
if ( i2c_slaves > = 0 ) {
printf ( " %u slave(s) found \n " , i2c_slaves ) ; // show summary
}
2018-03-11 17:51:53 +01:00
}
2018-03-21 23:20:39 +01:00
/** I2C menu commands */
2018-03-11 17:51:53 +01:00
static const struct menu_command_t busvoodoo_i2c_commands [ ] = {
2018-03-21 14:15:15 +01:00
{
' a ' ,
" action " ,
" perform protocol actions " ,
MENU_ARGUMENT_STRING ,
" [actions] " ,
& busvoodoo_i2c_command_actions ,
} ,
2018-03-11 17:51:53 +01:00
{
' s ' ,
" scan " ,
" scan for slave devices " ,
MENU_ARGUMENT_NONE ,
NULL ,
& busvoodoo_i2c_command_scan ,
} ,
} ;
struct busvoodoo_mode_t busvoodoo_i2c_mode = {
" i2c " ,
" Inter-Integrated Circuit " ,
& busvoodoo_i2c_setup ,
busvoodoo_i2c_commands ,
LENGTH ( busvoodoo_i2c_commands ) ,
& busvoodoo_i2c_exit ,
} ;