version   15/05/2025
rev ..........


Test MCP23017 avec PIC 18F27K42

ce test est en rapport avec le sujet : commande de Portail , sur Fantaspic

Hardware prototype
MCP23017 configuration
Test INTB MCP23017
Chronometrage de chaque changement d'etat port MB





Hardware :

Alimentation VCC= 5V
Carte Base 18F27K42
Led sur RA4 ..PIC18F
Fosc interne 64Mhz
MCP23017 sur breadboard
2 BP N.O. sur entree MB1 pin2 et MB34 pin 4
UART1 115200bds TX sur RC6, RX sur RC7
1 led sur MA4 pin 25
YAT terminal sur PC
Prolific TTL/USB cable
Pickit4 programmer

MCP23017 expander 16 I/O sur bus I2C




Prototype de test sur breadboard


Adresse I2C1 7 bits : 0x22

PIC Config via MCC :



Registres du MCP23017
/TABLE 1-6: CONTROL REGISTER SUMMARY (IOCON.BANK = 0)
// page 11
#define MCP23017_ADDR 0x22 // adresse 7 bits ! (A0=0 A1=1 A2=0 )
#define MCP_IODIRA 0x00
#define MCP_IODIRB 0x01
#define MCP_IPOLA 0x02
#define MCP_IPOLB 0x03
#define MCP_GPINTENA 0x04
#define MCP_GPINTENB 0x05
#define MCP_DEFVALA 0x06
#define MCP_DEFVALB 0x07
#define MCP_INTCONA 0x08
#define MCP_INTCONB 0x09
#define MCP_IOCONA 0x0A
#define MCP_IOCONB 0x0B
#define MCP_GPPUA 0x0C
#define MCP_GPPUB 0x0D
#define MCP_INTFA 0x0E
#define MCP_INTFB 0x0F
#define MCP_INTCAPA 0X10
#define MCP_INTCAPB 0x11
#define MCP_GPIOA 0x12
#define MCP_GPIOB 0x13
#define MCP_OLATA 0x14
#define MCP_OLATB 0x15

Datasheet MCP23017_features_01043a.pdf


Programme:
attention:
notation PortB pour le port B du PIC18F , mais MB pour le portB du MCP23017
Le MCP23017 est piloté en I2C à l'adresse (7bits) 0x22 ( pins adresses : A0=0,A1=1,A2=0)
Le port MB est configuré en (8) entrées
Le port MA en (8)sorties
Un changement d'etat sur le PORT MB genere une interruption via lla sortie INT B du MCP.


// --- Init MCP23017 pour interruptions sur PORT MB
void MCP23017_Init(void) {
I2C1_Write1ByteRegister(MCP23017_ADDR, MCP_IODIRB, 0xFF); // IODIRB = 0xFF (entrée)
I2C1_Write1ByteRegister(MCP23017_ADDR, MCP_GPINTENB, 0xFF); // Interrupt-on-change
I2C1_Write1ByteRegister(MCP23017_ADDR,MCP_DEFVALB,0xFF);
I2C1_Write1ByteRegister(MCP23017_ADDR,MCP_GPPUB,0xFF);
I2C1_Write1ByteRegister(MCP23017_ADDR, MCP_INTCONB, 0x00); // Comparaison avec l'état précédent
//I2C1_Write1ByteRegister(MCP23017_ADDR, MCP_INTCONB, 0xFF); // Comparaison avec l'étatDEFVALB
I2C1_Write1ByteRegister(MCP23017_ADDR, MCP_IOCONB,0x44); // Bank=0 INTB active low, open-drain
}

INTB MCP23017 relié à pin B1 du Port B PIC18F27K42
armement interruptions coté PIC
void __interrupt(irq(IRQ_IOC),high_priority) IOC_ISR(void)
{
unsigned char i;
const char *p2="ALERT\r\n";
if ( (IOCCF & 0x01)==1) // RC0
{
Led_Rouge=0; // allume led
k1_PWM=0;
k2_PWM=0;
PWM1_LoadDutyValue(k1_PWM); // plus de cde PWM sur le PONT H
PWM2_LoadDutyValue(k2_PWM);
IOCCF = 0x00;
}

if ((IOCBF & 0x02)==2) // RB1 <-INTB du MCP23017
{
mcp_timestamp = SMT1_GetTimeUs(); // Lecture "temps réel" dans l'ISR
mcp_flag = true;
IOCBF = 0x00;
}
}

* le traitement RC0 a un lien avec le traitement Surcharge Amperes du capteur INA229
On memorise le chrono (SMT1) en cours à l' instant de l'interrupt INTB


Test du flag INTB par interruption IOCB pin B1 du PIC18F
if (mcp_flag)
{
IT_Flag=I2C1_Read1ByteRegister(MCP23017_ADDR,MCP_INTFB);
CAPB=I2C1_Read1ByteRegister(MCP23017_ADDR,MCP_INTCAPB);
MCP_B = MCP23017_ReadGPIOB();
sprintf(CRam1," %lu.%lu mS IT_Flag = 0x%02X CAPB= 0x%02X",mcp_timestamp/1000,mcp_timestamp%1000, IT_Flag ,CAPB); // ok
Print(CRam1);
CRLF1();
mcp_flag = false;
}
le test INTB est OK !
le compteur SMT1 24 bits sert à chronometrer, certains évenements ou parties de codes.

exemple capture d'appui sur les Switches BP 2 et 4:
(0.640) N= 19 PWM1= 0 PWM2= 0 4.99 V 0.001 A . Seuil=0.600
(0.590) 6453.495 mS
IT_Flag = 0x00 CAPB= 0x02
(0.065) N= 20 PWM1= 0 PWM2= 0 4.99 V 0.001 A . Seuil=0.600
(0.136) 6535.074 mS
IT_Flag = 0x00 CAPB= 0x02
(0.521) N= 21 PWM1= 0 PWM2= 0 4.99 V 0.001 A . Seuil=0.600
(0.649) N= 22 PWM1= 0 PWM2= 0 4.99 V 0.001 A . Seuil=0.600
(0.144) 7133.053 mS
IT_Flag = 0x00 CAPB= 0x08
(0.000) 7212.565 mS IT_Flag = 0x00 CAPB= 0x08
(0.522) N= 23 PWM1= 0 PWM2= 0 4.99 V 0.001 A . Seuil=0.600

nota : on recupere quelle est la PIN MCP qui a générer l'interrupt et quel éait l'etat du port MB à cet instant

Problemes rencontrés :

Probleme sur Affichage des valeurs IT_Flag et CAPB issues de la capture du flag INTB MC23017
OK avec
sprintf(CRam1," %lu.%03d mS IT_Flag = 0x%02X CAPB= 0x%02X",mcp_timestamp/1000,mcp_timestamp%1000,IT_Flag,CAPB);
CAPB est bien vu à 0x02

(13:42:08.922) N= 21 PWM1= 0 PWM2= 0 4.99 V 0.001 A . Seuil=0.600 MCP_B = 0xFF
(13:42:09.561) N= 22 PWM1= 0 PWM2= 0 4.99 V 0.001 A . Seuil=0.600 MCP_B = 0xFF
(13:42:10.213) N= 23 PWM1= 0 PWM2= 0 4.99 V 0.001 A . Seuil=0.600 7231.436 mS IT_Flag = 0x00 CAPB= 0x02
(13:42:10.860) N= 24 PWM1= 0 PWM2= 0 4.99 V 0.001 A . Seuil=0.600 MCP_B = 0xFF

MAIS bad avec
sprintf(CRam1," %lu.%03d mS CAPB= 0x%02X",mcp_timestamp/1000,mcp_timestamp%1000,CAPB); // bad
CAPB est vu à 0x00 au lieu de 0x02

(13:45:07.669) N= 41 PWM1= 0 PWM2= 0 4.99 V 0.001 A . Seuil=0.600 MCP_B = 0xFD
(13:45:08.320) N= 42 PWM1= 0 PWM2= 0 4.99 V 0.001 A . Seuil=0.600 13507.815 mS CAPB= 0x00
(13:45:08.964) N= 43 PWM1= 0 PWM2= 0 4.99 V 0.001 A . Seuil=0.600 MCP_B = 0xFF

En fait le vrai probleme est en amont, sur l'affichage de mcp_timestamp, valeur unsigned long 32 bits..
et le resultat de mcp_timestamp%1000 que j'avais considré comme un int , puisque toujours inferieur à 1000 !
mais comme mcp_timestamp est un uL , le formattage devait etre perturbé, par 1 seule valeur 8 bits suivante..
alord que dans le test plus haut , j'ajoutait 2 valeurs 8 bits =16 bits ..bref , la cause exacte est enfouie dans le compilo !
Remede :
Caster le resulat de Mcp_timestamp%1000 en un unsigned Long
sprintf(CRam1," %lu.%lu mS CAPB= 0x%02X",mcp_timestamp/1000,mcp_timestamp%1000,CAPB);
OK !

Probleme majeur :
impossibilite de lire la valeur du port MB via l'interruption IOCB1
car l'I2C1 n'est pas ré-entrant. On ne peut lire le port MCP23017 QUE dans le MAIN ...
il s'ensuit un décalage temporel lié à la durée de la boucle principale , seule la datation de l'évenement
est temps réel ..mais pas le traitement ,qui sera Asynchrone, en retard , par rapport à l'évenement.
un peu de lectrure sur 5.1.2.1 Reentrancy - onlinedocs.microchip.com
Contre mesure :
multiplier l'occurence du test du flag dans le main program ...mais il faudrait AUSSI multiplier l'action lié
à l'evenement => donc INTB inutile, uniquement lire le MCP en pooling dans la boucle main..
sauf à l'utiliser directement pour une réaction au niveau Hardware ...
ou pour verifier un sequencement temporel ...
Diminuer tous les temps morts de la boucle principale ..

Les Evenements critiques ne doivent donc pas etre concernés par un resultat
de fonction NON réentrante ou récurssive.
Nota :
L'interrupt RC0 est OK, car c'est la sortie hardware du INA226 qui l'envoie et que le traitement n' a pas de lien avec
la lecture I2C de l'INA226 ....


Le code lié à ce test comporte aussi :
*la gestion d'un LCD 4x20 cars sur I2C1 ,
* module ITB2 driver de puissace pour moteur DC ( ici en 12V) ,piloté par 2 sortie PWM1 et PWM2 du PIC
* module de mesure Courant (et tension) moteur INA226 piloté via I2C1, avec sortie ALERT sur RC0 du PIC18F
(utilise un shunt 15Amp 150mv soit 0,01 ohm)
ALERT message à 0,6Amps (testé en frainant le rotor) => actions : arret par Enable=0 et Cdes PWM à zero.
* Liaison UART permettant de regler plusieurs valeurs de PWM1=xxxx et PWM2, et faire la commande M/A moteur: MA=1 ou MA=0
Affiche aussi Umoteur,I moteur ,PWM1,PWM2 ,et l'etat MCP23017
*gestion du chronometre utilisant le compteur SMT1 24 bits à +-1µS.

Init_I2C() 100Khz;
Test presence devices sur Bus I2C1
@ decimal # 68 soit @Device 7bits =
0X22 MCP23017 2 ports 8bits
@ decimal # 78 soit @Device 7bits = 0X27 PCF8754 for LCD 2x16cars
@ decimal # 128 soit @Device 7bits = 0X40 INA226 Current sensor


exemple d'affichage sur YAT terminal

(0.580) N= 40 PWM1= 0 PWM2= 0 0.00 V -0.001 A . Seuil=0.600
(0.581) N= 41 PWM1= 0 PWM2= 0 0.00 V -0.001 A . Seuil=0.600
(0.579) N= 42 PWM1= 0 PWM2= 0 0.00 V -0.001 A . Seuil=0.600
(0.580) N= 43 PWM1= 0 PWM2= 0 0.00 V -0.001 A . Seuil=0.600
(0.152)
12605.143 mS CAPB= 0xFD IT_Flag = 0x02
(0.063) N= 44 PWM1= 0 PWM2= 0 0.00 V -0.001 A . Seuil=0.600
(0.161)
12718.454 mS CAPB= 0xFF IT_Flag = 0x02
(0.052) N= 45 PWM1= 0 PWM2= 0 0.00 V -0.001 A . Seuil=0.600
(0.554) N= 46 PWM1= 0 PWM2= 0 0.00 V -0.001 A . Seuil=0.600
(0.581) N= 47 PWM1= 0 PWM2= 0 0.00 V -0.001 A . Seuil=0.600
..............
(0.135) MA=1
(0.423)
Recu :MA=1
(0.060) ITB2 Enabled
(0.000) N= 94 PWM1= 500 PWM2= 0 0.00 V -0.001 A . Seuil=0.600

(0.582) N= 122 PWM1= 500
PWM2= 0 5.34 V 0.034 A . Seuil=0.600
(0.581) N= 123 PWM1= 500 PWM2= 0 5.34 V 0.032 A . Seuil=0.600
(0.582) N= 124 PWM1= 500 PWM2= 0 5.34 V 0.033 A . Seuil=0.600
(0.581) N= 125 PWM1= 500 PWM2= 0 5.34 V 0.033 A . Seuil=0.600
(0.232) PWM1=1000
(0.326)
Recu :PWM1=1000
(0.009) Saisie OK PWM1-RC2 1000 98.0%
(0.051) N= 126 PWM1= 1000 PWM2= 0 5.34 V 0.034 A . Seuil=0.600
(0.585) N= 127 PWM1= 1000 PWM2= 0 5.30 V 0.070 A . Seuil=0.600
(0.579) N= 128 PWM1= 1000 PWM2= 0 5.29 V 0.082 A . Seuil=0.600
(0.581) N= 129 PWM1= 1000 PWM2= 0
5.24 V 0.139 A . Seuil=0.600
.......
(0.583) N= 149 PWM1= 1000 PWM2= 0 12.17 V 0.085 A . Seuil=0.600
(0.583) N= 150 PWM1= 1000 PWM2= 0 12.08 V 0.160 A . Seuil=0.600
(0.583) N= 151 PWM1= 1000 PWM2= 0
12.00 V 0.531 A . Seuil=0.600
...frainage moteur
(0.258)
ALERT
(0.324) N= 152 PWM1= 0PWM2= 0 0.00 V -0.001 A . Seuil=0.600


1ere valeur entre parenthese = durée boucle principale ~ 580mS

Lancement du programme :

Presentation :
BASE 18F27K42 + LCD4X20+ PWM1,2,3,4 Analog RA0,1,2,3
Directory :C:\MPLABX_Projects\18F27K42_PMW_CCP1234_2025
Project : 18F27K42_PMW_CCP1234_2025
Source : main.c , rev :_250512
Config Internal Fosc 64MHz
Autres :
LCD_4bits_I2C_2025-05, UART1_Functions.h , mcc.h,
A inclure:
Dialogue_Operateur_PC_via_UART_2023-0905

LCD_chars_Speciaux_2024.h, Eeprom : Eeprom...........
Hardware : BASE 18F27K42, I2C1: LCD4x20,INA226,IBT 2 Mosfet,MCP23017 + UART1
Schema: Carte_Portail_2_Vantaux_24v_H-en-MOSFET_INA226-HIP4082_FQP30N06L_V5.0.3.pdf by H.T.


Compiled May 12 2025 at 11:58:09 UTC version XC8 :2360

Init_I2C() 100Khz;
Test presence devices sur Bus I2C1
@ decimal # 68 soit @Device 7bits =
0X22 MCP23017 2 ports 8bits
@ decimal # 78 soit @Device 7bits = 0X27 PCF8754 for LCD 2x16cars
@ decimal # 128 soit @Device 7bits = 0X40 INA226 Current sensor



version Prototype : LCD Bleu a l'adresse 0x27 !
adresse LCD= 39 soit 0X27

Sequence d'Init LCD 4x20 via I2C1 PCF8574
.123456789A
Initialisation PWM1,2 avec FReq 3,9KHz (Timer2)

* PWM1 sur RC2 (TMR2)=0%
* PWM2 sur RC1 (TMR2)=0%

Init INA226 mesure de courant via I2C, shunt de 150mV pou 15Amps
Config INA226_CONF_REG,0x43FF (was 0x4127 )
Calibration register 05h (pour shunt 0,01 ohm et 8 Amps)
Mask/Alert MASK_EN_REG register 06h <- 0x8001
Alert MASK_EN_REG register 07h <- 2400 pour 0.6 A
Mesure de courant 0 mA
Seuil d'alerte 0.600 Amperes
INA Manufactuer 0x5449
INA Identifiant 0x2260
Fin de parametrage INA226... OK

Init MCP23017
Test differentes valeurs de Duty-cycle via le clavier terminal YAT
Activer la sortie PWMy avec MA=1 (arret via MA=0)
Entrer une valeur PWMy=xxxx puis <enter> avec y=1 ou 2 au clavier
Init SMT1 compteur 24b

Test chrono avec TMR6 x 10 boucles
Init TRM6 100mS
.......... SMT1 Nb Tics 1000102

Fin tempo de 1 sec via TMR6

N= 0 PWM1= 0 PWM2= 0 0.00 V -0.001 A . Seuil=0.600
N= 1 PWM1= 0 PWM2= 0 0.00 V -0.001 A . Seuil=0.600

A suivre ....
écriture sur port MA
clignotement sur sortie MCP ou PIC , avec Tmr6


last update : 15/05/2025
MPLAB IDE 6.0 et XC8
Directory: C:\MPLABX_Projects\18F27K42_PMW_CCP1234_2025
Project : 18F27K42_PMW_CCP1234_2025-0512.X.zip
main : main_18F27K42_MCP23017_0512.X.c
Chargeur :
18F27K42_PMW_CCP1234_2025-0512.X.hex


paulfjujo@free.fr


../common/mylogo_CI.jpg



Retour à l'index general