version  0.0  : 12/04/2021
rev 08/11/2021


Test ADXL345 et diverses fonctionalités du PIC 18F27K42 (dip28)

Version avec IT classiques mode LEGACY
Version avec IVT Interruptions vectorisées
*ADXL345 accelerometre 3 axes I2C







usage de MPLABX 5.40 et XC8
usage partiel de MCC

Base 18F27K42

HARDWARE

Alimentation VCC= 3.6V
Carte BASE 18F27K42

RA1 Entree EA1 ADC 12 bits (Potar 4.7k entre Vcc et Gnd avec curseur sur RA1 )
RA3 Sortie pour SQA 50 Trigger
RA4 sortie sur Led tirée au +Vcc via R=2,2k
RA6 sortie FOSC/4 (16MHz)
RB0 Entree Interrupt INT0
RB1 entree pour Forcage RTC valeurs Date Time par defaut

RC2 = Sortie NCO1 1Khz
RC3-RC4 Bus I2C1 sur RC3=SCL et RC4=SDA avec pull up de 2,7K
RC5 =PWM output -> MOSFET IRLZ14 -> Ampoule 12V 5W -- avec alim externe 12V
RC6-RC7 UART1 pins RC6 (TX) et RC7 (RX) -> cordon Prolific TTL/USB <-> Terminal YAT

MCLR ICSP VPP
RB6 ICSP Data
RB7 ICSP Clock

MCC:

configuration des pins :
images/t_ADXL345_18F27K42_MCC_config_2021-03.gif

La config Oscillateur Interne 64MHz, la gestion UART et L'ADC se fait ici Hors MCC,


UART1:
aiguillage des pins RC6 et RC7
RC6PPS = 0x13; //RC6->UART1:TX1;
U1RXPPS = 0x17; //RC7->UART1:RX1;
// SPEED
19200 bds at FOSC =64MHz
// BRG=833 U1BRGL = 0x40; U1BRGH=3;
U1CON0=0; // MODE=0000 Asynchronous 8-bit UART mode Auto Bauds=ABDEN=0
U1BRGH = BRG/256;
U1BRGL = BRG%256;
U1CON0bits.BRGS=1;
U1CON0bits.TXEN=1;
U1CON0bits.RXEN=1;
I2C1 :
L'aiguillage des pins RC3 et RC4 pour I2C1 Hardware
RC3PPS = 0x21; //RC3->I2C1:SCL1;
I2C1SCLPPS = 0x13; //RC3->I2C1:SCL1;
RC4PPS = 0x22; //RC4->I2C1:SDA1;
I2C1SDAPPS = 0x14; //RC4->I2C1:SDA1;
NCO1 Numerical Controlled Oscillateur
aiguillage sortie NCO1 sur Pin RC2 sur
RC2PPS = 0x26; //RC2->NCO1:NCO1;
PWM5 Pulse Width Modulation
aiguillage pin RC5
RC5PPS = 0x0D; //RC5->PWM5:PWM5;

Devices découverts sur le bus I2C1
(13:36:54.196) Test Presence I2C device (adressage 8 bits)
(13:36:54.196) @ decimal # 120 soit @Device7bits = 0X3C
OLED SSD1306
(13:36:54.228) @ decimal # 166 soit @Device7bits = 0X53
ADXL345 board
(13:36:54.262) @ decimal # 174 soit @Device7bits = 0X57
EEPROM 512bytes
(13:36:54.294) @ decimal # 208 soit @Device7bits = 0X68
RTC DS3231



Gestion des interrupts
Mode IVT non activé => donc mode Legacy, classique.
Mais modification de la partie interrupt_manager.c généré par MCC
High (vecteur 0x08) pour UART et I2C et Low (vecteur 0x18) pour Timer2
UART1 :


Nota: la partie I2C1 en High interrupt (générée par MCC) reste inchangée.


cela permet de traiter l'envoi de 2 commandes prédeterminées ,via le clavier Terminal YAT
Help
ou mise à jour RTC via la séquence
U;JJ;MM;AA;HH;MM;JS;#
exemple U;11;04;21;14;47;07;# pour le 11 avril 2021 14H47 Dimanche

TMR2 en Low interrupt :



init du Timer2
void TMR2_Init(void)
{
// Set TMR2 to the options selected in the User Interface
// T2PSYNC Not Synchronized; T2MODE Software control; T2CKPOL Rising Edge; T2CKSYNC Not Synchronized;
T2CLKCON = 0x01; // T2CS FOSC/4 =
16MHz sinon 0x05 pour 500Khz
T2HLT = 0x00;
T2RST = 0x08; // T2RSEL PWM5OUT;
T2PR = 0xFF; // PR2 255;
T2TMR = 0x00; // TMR2 0;
PIR4bits.TMR2IF = 0; // Clearing IF flag.
// T2CON = 0x83; // 0x03=avec TMR2ON=0=OFF 0x83=avec TMR2ON=1=ON; T2CKPS 1:1; T2OUTPS 1:4; 64µS
T2CON = 0x60 | 0x07 ; // Prescaler =1/64 Poscaler=1/8 => 1/128 ticks=
8192uS
}


Calcul période tick :
T2CLKCON=>FOSC/4 =>16MHz => 0.0625µS
Effet multiplicateur via (Prescaler * Postscaler) = 64 x 8= 512
PR2 compteur +1 =255+1=256
periode = 0.0625 * 512 *256 = 8192 µS
Dans l'interrupt Timer2 tick2_count évolue jusqu'à 122
122 * 8192 µs => ~1seconde

Nota: en mode Timer libre , le POSTSCALER est bien pris en compte !




------------------------------


SMT1 compteur 24bits
Compteur pouvant utiliser directement FOSC 64MHz !
soit une resolution proche de + - 0.015625 µS
sur une plage de durée maxi de 262mS, sans overflow.
utilisé , par exemple ,pour chronometrage de l'execution d'une portion de code

SMT1 Init



Usage :
exemple test fonction delay 10mS
CPrint(" Test compteur 24 bits SMT1 sur FOSC=64MHz \r\n");
CPrint(" Resolution compteur +- 16 nanoSec (maxima= 262mS)\r\n");
ST=&SMT1_Measure; // pointeur Byte sur debut entier long 32 bits
CPrint(" Start SMT1 for test delay 10mS\r\n");
SMT1_Measure=0;
SMT1STATbits.RST=1;
SMT1CON1bits.SMT1GO=1;
__delay_ms(10);
SMT1CON1bits.SMT1GO=0;
txt=&TEXTE[0];
*(ST)=SMT1TMRL;
*(ST+1)=SMT1TMRH;
*(ST+2)=SMT1TMRU;
*(ST+3)=0;
CPrint( " Stop. SMT1 tics avec ultoa -> ");
ultoa(txt,SMT1_Measure,10);
Print(txt);
sprintf(txt," , et (via sprintf) -> %lu uS ",SMT1_Measure>>6);
Print(txt); CRLF1();


résultat :
Test compteur 24 bits SMT1 sur FOSC=64MHz
Resolution compteur +- 16 nanoSec (maxima= 262mS)
Start SMT1 for test delay 10mS
Stop. SMT1 tics avec ultoa -> 640008 , et (via sprintf) -> 10000 uS


Test Acquistion de 128 mesures ADC 12bits
Start SMT1 pour 128 mesures ADC12 bits
Stop SMT1 tics avec ultoa -> 328124 , soit (avec sprintf) -> 5126 uS
pour 1 mesure ADC12bit + stockage => 40 uS

(mesure ADC non optimisée !)





ADXL345 I2C
Accelerometre 3 axes , sorties en I2C
ADXL345 board adresse I2C =decimal # 166 soit @Device7bits = 0X53
Pour les details Hardware et device , voir ma version en C18
et ce lien http://www.geekmomprojects.com/gyroscopes-and-accelerometers-on-a-chip/

Init ADXL
void Init_ADXL345(void)
{
ADXL345 =ADXL345_ADRESS;
I2C1_Write1ByteRegister( ADXL345, BW_RATE,0x0D);
I2C1_Write1ByteRegister( ADXL345, FIFO_CTL,0x9F);
I2C1_Write1ByteRegister( ADXL345, POWER_CTL,0x08);
}


L'ADXL345 DOIT REPONDRE à l'init :
Init ADXL345
Device id= 229 ... OK
Power CTRL= 8
BW_RATE= 13


exemple de réponse ADXL345 sur lecture des Registres ..
(15:24:54.049) ADXL345 Xa= 117 Ya= -230 Za= 43 ; Angle : Xa= 26.57; Ya=-61.54 ; Za=65.61
(15:24:55.160) 11/04/21 15H25M34S ; 19.00°C; EA=0.12V PWM= 3 %; Cpt_T2= 7
(15:24:55.421) ADXL345 Xa= 116 Ya= -229 Za= 43 ; Angle : Xa= 26.47; Ya=-61.62 ; Za=65.68
(15:24:56.533) 11/04/21 15H25M35S ; 19.00°C; EA=0.12V PWM= 3 %; Cpt_T2= 8
(15:24:56.793) ADXL345 Xa= 116 Ya= -229 Za= 43 ; Angle : Xa= 26.47; Ya=-61.62 ; Za=65.68


je n'ai pas pour l'instant, d'application particuliere pour ce device..
Test avec Potar ADC -> EA1 /4 => commande 0 à 1023 (0 à 100%) PWM5
-> MOSFET IRLZ14 -> lampe 5W 12V


------------------------------

La RTC DS3231 et e LCD OLED SSD1306
sont utilisés ici pour afficher , via la boucle principale du programme:
la date et l'heure sur la 1ere Ligne
La valeur de EA1 en Volt et le pourcentage PWM5 sur la 2 em ligne
La valeur ADXL345 Xa sur la 3em ligne
Les 2 autres valeurs Ya et Za sur la 4em ligne

L'UART permet de suivre le programme et alimente le fichier log du terminal YAT
YAT-Log-ADXL345_18F27K42_20210411.log

Start Programme :

Projet MPLABX :ADXL345_18F27K42_2021
Compile le Apr 12 2021 a 15:57:06 UTC
avec version XC8 : 2100
Test ADXL345 I2C avec OLED , RTC, UART rev avril 2021
Hardware : BASE 18F27K42 FOSC interne =64MHz
UART1 Hadrware RC6=TX RC7=RX 19200,8,N,1 Interrupt High sur RX
TIMER2 free mode Interrupt Low avec tick=8192µS 122 boucles => 1sec
Entree ADC EA1 12 bits sur RA1 pour consigne PWM5
TIMER4 lié à PWM5 ticks=64µS
Module PW5 10 bits, (lié à TMR4 ) ,sortie RC5
Sortie NCO1 10Khz sur RC2
SQA50 synchro Analyser : Sortie 10Khz sur RA3
Sortie FOSC/4 sur RA6
NCO Numerical Controlled Oscillateur : Sortie sur RC2
choix OLED 0,96 128x32 Jaune/bleu ou Mini OLED via RB2 input
usage de SMT1 compteur 24bits pour chronometrage
Module ADXL345 sur bus I2C1
RTC DS3231 sur le bus I2C1 RC3=SCL RC4=SDA
Forçage Date et Heure RTC via Pin RB1
MAJ RTC via UART1 avec RX Interrupt

Init NCO1 1Khz sur RC2
NCO1 1Khz L = 98 soit 0x62 , H= 16 soit 0x10, U= 0 soit 0X 0

Init Timer4 associé à PWM5 , tick=64µS
Init Timer2 en mode free, tick=8192µS

Test compteur 24 bits SMT1 sur FOSC=64MHz
Resolution compteur +- 16 nanoSec (maxima= 262mS)
Start SMT1 for test delay 10mS
Stop. SMT1 tics avec ultoa -> 640008 , et (via sprintf) -> 10000 uS

Init ADC EA1
Start SMT1 pour 128 mesures ADC12 bits
Stop SMT1 tics avec ultoa -> 325164 , soit (avec sprintf) -> 5080 uS
1 mesure ADC12bit + stockage , en 39 uS
Moy. Table de 128 mes. EA1_Avg=149 pts, soit 0.131V

NCO1 1Khz L =215 soit 0xD7 , H=163 soit 0xA3, U= 0 soit 0X 0


Test Presence I2C device (adressage 8 bits)
@ decimal # 120 soit @Device7bits = 0X3C OLED SSD1306
@ decimal # 166 soit @Device7bits = 0X53 ADXL345 board
@ decimal # 174 soit @Device7bits = 0X57 EEPROM 512bytes
@ decimal # 208 soit @Device7bits = 0X68 RTC DS3231
..etc


Le Projet MPLABX V5.30 et XC8

images/t_Projet_MPLABX_UART1_IT_TMR2_IT_I2C1_OLED_RTC_ADXL345_PWM5_SMT1_NOC1_18F27K42_2021-04.gif


MPLABX Package :
UART1_IT_TMR2_IT_I2C1_OLED_RTC_ADXL345_PWM5_SMT1_NOC1_18F27K42_2021-0414.zip
main programme : main_ADXL345_18F27K42_20210414_X.c
accelerometre ADXL :
ADXL_345.c
chargeur : UART1 .....hex





Version avec IVT usage des Interruptions Vectorisées


Nota : seule la partie I2C1 est générée via MCC



Interruptions TMR2,TMR6,UART1 RX, ADC,RB0
gérée via IVT :
void __interrupt(irq(U1RX),base(8)) UART1_rx_vect_isr(void);
void __interrupt(irq(TMR6),base(8),low_priority) TMR6_ISR(void);
void __interrupt(irq(TMR2),base(8),low_priority) TMR2_ISR(void);
void __interrupt(irq(INT0),base(8),low_priority) INT0_ISR(void);
void __interrupt(irq(AD),base(8),low_priority) ADCC_ISR(void);
void __interrupt(irq(default),base(8),low_priority) Default_ISR(void);

et I2C via MCC
void __interrupt(irq(I2C1TX,I2C1RX,I2C1E,I2C1),base(8)) I2C1_ISR()

MCU avec FOSC interne 64MHz
CLKOUT 16MHz sur RA6
PWM5 10 bits sur RC5
NCO1 output 10KHz sur RC2
UART1 RC6 TX RC7 RX à 115200 bauds
SQA sortie RA3
ADC1 12 bits entree sur RA1
Bus I2C1 sur RC3 SCL et RC4 SDA
RTC DS32131 sur bus I2C1

exemple IVT RX UART


void __interrupt(irq(U1RX),base(8)) UART1_rx_vect_isr()
{
static char cx;
// U1TXB='H'; // pour debugging only
if ( (PIR3bits.U1RXIF==1) && (PIE3bits.U1RXIE ==1) )
{
c1=U1RXB;
// U1TXB='*'; // echo
if ((c1==13) || (i1>UART1_RX_BUFFER_SIZE-1))
{
Flag_Buffer1=1;
if(PIR3bits.U1RXIF) Buffer1[i1]=U1RXB;
Buffer1[i1]=0;
Index1=i1;
i1=0;
// PIE3bits.U1RXIE =0;
}
else
{
Buffer1[i1]=c1;
i1++;
Index1=i1;
if(PIR3bits.U1RXIF)
{
Buffer1[i1]=U1RXB;
i1++;
Index1=i1;
}
}
}
}

Exemple Timer2 , en Low Priority :

void __interrupt(irq(TMR2),base(8),low_priority) TMR2_ISR()
{
static volatile uint16_t TMR2_Ticks = 0;
// clear the TMR2 interrupt flag
PIR4bits.TMR2IF = 0;
if (++TMR2_Ticks >= TMR2_INTERRUPT_TICKS) // 4 => 32.768mS
{
Cpt_T2++;
TMR2_Ticks = 0;
}
}


Probleme avec ultoa non reconu avec la version compilateur C99
=> mais OK avec usage de la version C90
why ?


Terminal YAT : 115200,8,N,1




Projet MPLABX avec XC8 V2.32 :
IVT_Test_18F27K42_20210416.zip
main source : main_IVT_Test_18F27K42_20210416.c
Chargeur : IVT_Test_18F27K42.X.production.hex

nota : ce programme est OK , mais nettement améliorable ,car comporte des tonnes de warnings !

Utilitaire : 18F27K42_All_Datas_Help.zip





paulfjujo@free.fr


../common/mylogo_CI.jpg



Retour à l'index general