Hello dear all,
I would like to establish an I2C communication between the MSP432 and the AD5933 to read and write at the AD5933 level. The MSP432 being the master and the AD5933 the exclave. I wrote my code which I share with you but nothing happens. I don't know where the problem is because I don't have an oscilloscope. Can you help me.
#include <msp432p401r.h>
#include <stdint.h>
#include <stdio.h>
#define SLAVE_ADDRESS 0x0D
#define PCMKEY_value 0x695A0000
#define CS_KEY_value 0x0000695A
#define CTRL_1 0x81 // Registre control 1
uint8_t RXData;
// Delay function
void delay(int n)
{
int i, j;
for (j = 0; j < n; j++)
for (i = 0; i < 1000; i++);
}
void DCO_clock(int clock_speed) {
CS->KEY = CS_KEY_value;
switch (clock_speed) {
case 0: {
CS->CTL0 = CS_CTL0_DCORSEL_0; // 1.5MHz
break;
}
case 1: {
CS->CTL0 = CS_CTL0_DCORSEL_1; // 3MHz
break;
}
case 2: {
CS->CTL0 = CS_CTL0_DCORSEL_2; // 6MHz
break;
}
case 3: {
CS->CTL0 = CS_CTL0_DCORSEL_3; // 12MHz
break;
}
case 4: {
CS->CTL0 = CS_CTL0_DCORSEL_4; // 24MHz
break;
}
case 5: {
PCM->CTL0 = PCMKEY_value + PCM_CTL0_AMR_1; // LDO_Vcore1 choice
while ((PCM->CTL1 & PCM_CTL1_PMR_BUSY) != 0);
PCM->CTL0 = PCMKEY_value + PCM_CTL0_AMR_5; // DCDC_Vcore1 choice
while ((PCM->CTL1 & PCM_CTL1_PMR_BUSY) != 0);
FLCTL->BANK0_RDCTL = FLCTL_BANK0_RDCTL_WAIT_3; // wait state = 3 for read in RAM bank0
FLCTL->BANK1_RDCTL = FLCTL_BANK1_RDCTL_WAIT_3; // wait state = 3 for read in RAM bank1
CS->CTL0 = CS_CTL0_DCORSEL_5; // 48MHz
break;
}
}
CS->KEY = 0;
}
void clock(void) {
CS->KEY = CS_KEY_value;
CS->CTL1 = CS_CTL1_SELA_3 + CS_CTL1_SELS_3 + CS_CTL1_SELM_3;
CS->KEY = 0;
}
void I2C_Init(void)
{
UCB0CTLW0 |= UCSWRST; //reset the l'I2C for modification registers
P1->SEL0 |= BIT6 + BIT7; //SDA = P1.6 et SCL = P1.7
P1->SEL1 &= ~(BIT6 + BIT7);
P1->REN |= BIT6 | BIT7; // Activation of internal pull-up resistors
P1->OUT |= BIT6 | BIT7; // Configuration of pull-up resistors
EUSCI_B0->CTLW0 = UCMST + UCMODE_3 + UCSYNC + UCSSEL_2 + UCSWRST; //I2C type communication in master mode + synchro, SMCLK, and maintained reset
EUSCI_B0->CTLW0 = 30; //fSCL = SMCLK/30 = 100kHz
EUSCI_B0->CTLW0 &= ~UCSWRST; //fonctionnement normal
EUSCI_B0->IE |= UCRXIE | UCNACKIE | UCBCNTIE;
}
/*
* FUNCTION THAT MANAGES INTERRUPTIONS
*
* The interest of this function is to process the different sources of interruptions that can occur during I2C operations, such as:
UCNACKIFG: This flag is set when the I2C module receives a NACK (Not Acknowledge) during a data transmission. In the corrected code, it is used to reset the UCNACKIFG flag, enable sleep-on-exit mode (SCB_SCR_SLEEPONEXIT), and restart transmission by setting the UCTXSTT bit to 1.
UCRXIFG0: This flag is set when data is successfully received by the I2C module. In the corrected code, it is used to reset the UCRXIFG0 flag, disable sleep-on-exit mode (SCB_SCR_SLEEPONEXIT), and store received data in the RXData variable.
UCBCNTIFG: This flag is set when the number of bytes expected during an I2C operation is reached. In the corrected code, it is used to reset the UCBCNTIFG flag, enable sleep-on-output mode (SCB_SCR_SLEEPONEXIT), and invert the state of pin P1.0 (P1OUT ^= BIT0).
*/
void EUSCIB0_IRQHandler(void)
{
if (UCB0IFG & UCNACKIFG)
{
UCB0IFG &= ~UCNACKIFG;
SCB->SCR |= SCB_SCR_SLEEPONEXIT_Msk;
UCB0CTLW0 |= UCTXSTT;
}
if (UCB0IFG & UCRXIFG0)
{
UCB0IFG &= ~UCRXIFG0;
SCB->SCR &= ~SCB_SCR_SLEEPONEXIT_Msk;
RXData = UCB0RXBUF;
}
if (UCB0IFG & UCBCNTIFG)
{
UCB0IFG &= ~UCBCNTIFG;
SCB->SCR |= SCB_SCR_SLEEPONEXIT_Msk;
P1OUT ^= BIT0;
}
}
/*
* Writing a byte (Write Byte/Command Byte):
1.The master device sends a start condition (START) on SDA.
2.The master sends the 7-bit slave address followed by the write bit (0).
3. The addressed slave device sends an ACK on SDA.
4.The master sends a register address.
5.The slave sends an ACK on SDA.
6.The master sends a data byte.
7.The slave sends an ACK on SDA.
8.The master sends an end condition (STOP) on SDA to terminate the transaction.
*/
// Function to write a byte in an AD5933 register via the I2C interface
void I2C_writeRegister(uint8_t reg, int data)
{
EUSCI_B0->CTLW0 |= EUSCI_B_CTLW0_TR; // Transmission
EUSCI_B0->CTLW0 |= EUSCI_B_CTLW0_TXSTT; // Start signal generation
while (!(EUSCI_B0->IFG & EUSCI_B_IFG_TXIFG0)); // Waiting for start signal to be sent
EUSCI_B0->I2CSA = SLAVE_ADDRESS; // Send AD5933 address
while (!(EUSCI_B0->IFG & EUSCI_B_IFG_TXIFG0)); // Waiting for start signal to be sent
EUSCI_B0->TXBUF = reg; // Send register address
while (!(EUSCI_B0->IFG & EUSCI_B_IFG_TXIFG0)); // Waiting for register address to be sent
EUSCI_B0->TXBUF = data; // Sending data
while (!(EUSCI_B0->IFG & EUSCI_B_IFG_TXIFG0)); // Waiting for data to be sent
EUSCI_B0->CTLW0 |= EUSCI_B_CTLW0_TXSTP; // Waiting for data to be sent
while (EUSCI_B0->CTLW0 & EUSCI_B_CTLW0_TXSTP); // Waiting for the end of the transmission
// Handwriting verification
if (EUSCI_B0->IFG & EUSCI_B_IFG_NACKIFG)
{
// Failed to write
// Handle the error accordingly
printf("Write failed");
}
else
{
// The write was successful
printf("Number %u write operation completed successfully", data);
}
}
/*
* Reading a byte (Receive Byte):
1.The master device sends a start condition (START) on SDA.
2.The master sends the 7-bit slave address followed by the read bit (1).
3. The addressed slave device sends an ACK on SDA.
4.The master receives a data byte.
5.The master sends a NO ACK on SDA (the slave must verify that the master has received the data).
6.The master sends an end condition (STOP) on SDA and the transaction ends.
*/
// Function to read a register from the AD5933 via the I2C interface
// Function to write a byte in an AD5933 register via the I2C interface
uint8_t I2C_readRegister(uint8_t reg)
{
uint8_t AD5933_address = (SLAVE_ADDRESS << 1) | 0x01; // Combination of slave address and read bit
EUSCI_B0->CTLW0 |= EUSCI_B_CTLW0_TR; // Transmission
EUSCI_B0->CTLW0 |= EUSCI_B_CTLW0_TXSTT; // // Generate the start signal
EUSCI_B0->I2CSA = AD5933_address; // Send the address of the register to write
while (!(EUSCI_B0->IFG & EUSCI_B_IFG_TXIFG0)); // Wait for start signal to be sent
EUSCI_B0->TXBUF = reg; // // Send register address
while (!(EUSCI_B0->IFG & EUSCI_B_IFG_TXIFG0)); // // Wait for register address to be sent
EUSCI_B0->CTLW0 &= ~EUSCI_B_CTLW0_TR; // Reception
EUSCI_B0->CTLW0 |= EUSCI_B_CTLW0_TXSTT; // // Generate a repetition of the start signal
while (EUSCI_B0->CTLW0 & EUSCI_B_CTLW0_TXSTT); // Wait for the end of the start signal repetition
EUSCI_B0->CTLW0 |= EUSCI_B_CTLW0_TXSTP; // Generation of the stop signal
while (!(EUSCI_B0->IFG & EUSCI_B_IFG_RXIFG0)); // // Wait for the reception of the data
// Verification of the reading
if (EUSCI_B0->IFG & EUSCI_B_IFG_NACKIFG)
{
// Failed to read
printf("Failed to read register %u", reg);
}
else
{
// The write was successful
printf("%u register read operation completed successfully", reg);
}
RXData = EUSCI_B0->RXBUF; // Lecture de la donnée reçue
return RXData;
}
/**
* main.c
*/
void main(void)
{
WDT_A->CTL = WDT_A_CTL_PW | WDT_A_CTL_HOLD; // stop watchdog timer
clock();
DCO_clock(1);
I2C_Init();
// Exemple d'écriture et de lecture d'un registre de l'AD5933
delay(100); // Délai de stabilisation de l'AD5933
I2C_writeRegister(CTRL_1, 2); // Écriture dans le registre de contrôle 1
uint8_t data = I2C_readRegister(CTRL_1); // Lecture du registre de contrôle 1
printf("Data read from register: %u\n", data);
}
