Migro aquí el post que tenía en LCD I2C.
Hace unos días a raíz de este
hilo de raphik se me ocurrió la idea de montar un circuito de relés y botones bajo el bus I2C, poco a poco iré agregando sensores y alguna pantalla, es increíble la versatilidad y capacidad de expansión que tiene.
Soy bien consiente de mi carencia de conocimientos en todo esto, pero con pasión, empeño e imaginación lo voy sacando. (mas que nada, confío en la ayuda de la gente de éste foro
)
Los módulos de expansión I2C que estoy usando son los PCF8574, conectados en paralelos, uno tienes salidas a "8" relé y el otro tiene "8" entradas de señal de un teclado tactil.
El modo de instalar los módulos están descritos
=>por raphik aquí en este hilo <=.
Como los módulos de expansión se han de trabajar en hexadecimal o decimal uso un soft conversor de base bidireccional "GHex" (dec, Octal, hex, binario y ASCII... recomendable para familiarizarse con todo esto)
raphik había comentado esto, confirmando una sospecha que ya tenía...
Si lo que queremos en realidad es activar una o más patillas dejando invariable el resto, no queda otra que tirar del operador binario OR. Primero habría que conocer el estado previo de todas las patillas, luego habría que calcular el valor a enviar y por último enviarlo.
Esta parte la solucioné de esta manera creando un "nuevo device" (que crea una nueva base GPIO) que para mover los relé veo que es simple y suficiente, aunque hay algo que me dice que puede no ser lo mas eficiente.
echo pcf8574 0x39 > /sys/bus/i2c/devices/i2c-0/new_device
echo pcf8574 0x38 > /sys/bus/i2c/devices/i2c-0/new_device
Las dos nuevas GPIOBase
find /sys/class/gpio/gpio*
/sys/class/gpio/gpio481
/sys/class/gpio/gpio483
/sys/class/gpio/gpiochip458 #base nueva GPIO
/sys/class/gpio/gpiochip466 #base nueva GPIO
/sys/class/gpio/gpiochip474
/sys/class/gpio/gpiochip506
Se ve la carga en el dmesg (extracto)
i2c 0-0039: uevent
<7>[ 268.825591] pcf857x 0-0039: probe
<7>[ 268.825666] i2c i2c-0: master_xfer[0] R, addr=0x39, len=1
<6>[ 268.826457] pcf857x 0-0039: probed
<7>[ 268.830081] i2c i2c-0: client [pcf8574] registered with bus id 0-0039
<6>[ 268.830133] i2c i2c-0: new_device: Instantiated device pcf8574 at 0x39
<7>[ 281.481288] i2c 0-0038: uevent
<7>[ 281.481799] pcf857x 0-0038: probe
<7>[ 281.481875] i2c i2c-0: master_xfer[0] R, addr=0x38, len=1
<6>[ 281.482559] pcf857x 0-0038: probed
<7>[ 281.486199] i2c i2c-0: client [pcf8574] registered with bus id 0-0038
<6>[ 281.486263] i2c i2c-0: new_device: Instantiated device pcf8574 at 0x38
---------- Y la carga de todo el Mapeado...
i2c i2c-0: master_xfer[0] W, addr=0x39, len=1
<7>[ 745.166910] i2c i2c-0: master_xfer[0] W, addr=0x39, len=1
<7>[ 752.678994] i2c i2c-0: master_xfer[0] W, addr=0x39, len=1
<7>[ 752.680005] i2c i2c-0: master_xfer[0] W, addr=0x39, len=1
<7>[ 765.262345] i2c i2c-0: master_xfer[0] W, addr=0x39, len=1
<7>[ 765.263334] i2c i2c-0: master_xfer[0] W, addr=0x39, len=1
Estoy usando este script pra controlar el estado o salida "./gpio.sh 1 out 0 | ./gpio.sh 1 out 1"
#!/bin/sh
show_usage()
{
printf "\ngpio.sh <gpio pin number> [in|out [<value>]]\n"
}
if [ \( $# -eq 0 \) -o \( $# -gt 3 \) ] ; then
show_usage
printf "\n\nERROR: incorrect number of parameters\n"
exit 255
fi
GPIOBASE=`cat /sys/class/gpio/gpiochip*/base | head -n1`
GPIO=`expr $1 + $GPIOBASE`
#doesn't hurt to export a gpio more than once
(echo $GPIO > /sys/class/gpio/export) >& /dev/null
if [ $# -eq 1 ] ; then
cat /sys/class/gpio/gpio$GPIO/value
exit 0
fi
if [ \( "$2" != "in" \) -a \( "$2" != "out" \) ] ; then
show_usage
printf "\n\nERROR: second parameter must be 'in' or 'out'\n"
exit 255
fi
echo $2 > /sys/class/gpio/gpio$GPIO/direction
if [ $# -eq 2 ] ; then
cat /sys/class/gpio/gpio$GPIO/value
exit 0
fi
VAL=$3
if [ $VAL -ne 0 ] ; then
VAL=1
fi
echo $VAL > /sys/class/gpio/gpio$GPIO/value
En /etc/rc.local queda establecido al final del arranque en que estado está el circuito, es decir, los 8 del teclado como "in". pero aquí es donde viene el
problema de esta configuración, que el
logread solo escucha los eventos que están predefinidos en la programación del la placa del router, es decir, aquellos gpios que controlan botones físicos del router o los que corresponden a los led.
No he encontrado aún la manera de que el router se entere de los eventos que están sucediendo en las GPIO "libres" y tampoco escucha las instrucciones "de manera precisa" enviadas con los comandos de I2C-tools, en cualquier caso la salida es esta y no sirve para nada.
Wed Oct 11 17:52:28 2017 kern.debug kernel: [ 3009.519362] i2c i2c-0: master_xfer[0] W, addr=0x39, len=1
Wed Oct 11 17:52:28 2017 kern.debug kernel: [ 3009.521031] i2c i2c-0: master_xfer[0] W, addr=0x39, len=1
Supongo que hay que registrar en el kernel el nuevo boton a usar, o decirle al logread que preste atención a determinadas salidas GPIO pero no he visto forma de hacerlo.
Esta manera es lo que buscaba en un inicio, pero por "falta de recursos cerebrales" he seguido al menos de momento con la solución de tratarlos como GPIO, Aunque lo próximo que me viene de camino son sensores y de aquí no me escaparé... jejeje ya tendré que hacerlo en hex...
Lo vemos con un ejemplo: activar P7 preservando el estado de las demás salidas. Sabiendo que 0x10000000 equivale a 0x80,
Código:
prevState=$((i2cget -y 0 0x27)) # lectura del estado actual
newState=$(($prevState | 0x80)) #cálculo del nuevo valor respetando el estado previo
i2cset -y 0 0x27 $newState # escritura del nuevo estado