lab3_I2C
lab3_I2C
LABORATORY REPORT
DEVICE NETWORKS
2. Hardware
3. Software
3.3. Code
Master
The code is added in between /* USER CODE BEGIN Includes */ and /* USER
CODE END Includes */
uint16_t slaveADDR = 0x12<<1;
uint16_t slaveMemADDR = 0x45<<1;
uint8_t TxData[6] = {0};
uint8_t RxData[6];
uint16_t readValue;
The code is added in between /* USER CODE BEGIN BEGIN 2*/ and /* USER
CODE END BEGIN 2*/
HAL_ADC_Start(&hadc1);
The code is added in between /* USER CODE BEGIN WHILE*/ and /* USER CODE
END WHILE*/
HAL_ADC_PollForConversion(&hadc1,1000);
readValue = HAL_ADC_GetValue(&hadc1);
TxData[5] = readValue>>4;
HAL_I2C_Master_Transmit(&hi2c1, slaveADDR, TxData, 6, 1000);
HAL_I2C_Mem_Read(&hi2c1, slaveADDR, slaveMemADDR, 0, RxData, 6,
1000);
HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13);
HAL_Delay(RxData[3]);
Slave:
The code is added in between /* USER CODE BEGIN Include*/ and /* USER CODE
END Include*/
#include "i2c_slave.h"
The code is added in between /* USER CODE BEGIN 0*/ and /* USER CODE END
0*/
uint8_t i2c_rcv = 255; // Data received from I2C master
uint32_t time_start = 0; // Start time for blinking
uint8_t stat_LED = 0; // LED state: 1 = ON, 0 = OFF
uint8_t value_pot = 0; // Scaled potentiometer value (0-255)
volatile uint8_t i2c_rx_data = 0; // Buffer for received I2C data
volatile uint8_t i2c_tx_data = 0; // Buffer for transmitted I2C data
uint8_t ScaleADCToByte(uint16_t adc_value) {
return (uint8_t)((adc_value * 255) / 4095);
}
The code is added in between /* USER CODE BEGIN 2*/ and /* USER CODE END
2*/
if (HAL_I2C_EnableListen_IT(&hi2c1) != HAL_OK)
{
Error_Handler();
}
HAL_ADC_Start(&hadc1);
time_start = HAL_GetTick();
The code is added in between /* USER CODE BEGIN WHILE*/ and /* USER CODE
END WHILE*/ .
// Read potentiometer via ADC
if (HAL_ADC_PollForConversion(&hadc1, 10) == HAL_OK) {
uint16_t adc_value = HAL_ADC_GetValue(&hadc1);
value_pot = ScaleADCToByte(adc_value);
i2c_tx_data = value_pot; // Update transmit buffer
I2C_REGISTERS[3] = i2c_tx_data;
}
// Blink LED based on received value
i2c_rcv = I2C_REGISTERS[4];
float interval = (i2c_rcv == 0) ? 100 : (1000 * ((float)i2c_rcv / 255.0));
if ((HAL_GetTick() - time_start) > interval) {
stat_LED = !stat_LED;
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, stat_LED ? GPIO_PIN_RESET :
GPIO_PIN_SET); // PC13 active-low
time_start = HAL_GetTick();
}
The code is added in between /* USER CODE BEGIN I2C1_Init 1*/ and /* USER
CODE END I2C1_Init 1*/ .
hi2c1.Instance = I2C1;
hi2c1.Init.ClockSpeed = 100000;
hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2;
hi2c1.Init.OwnAddress1 = 36;
hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
hi2c1.Init.OwnAddress2 = 0;
hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
if (HAL_I2C_Init(&hi2c1) != HAL_OK)
{
Error_Handler();
}
4. Results
4.2. Picture
Figure:
Master Debugger:
Slave Debugger:
Appendix
i2c_slave.h
#ifndef INC_I2C_SLAVE_H_
#define INC_I2C_SLAVE_H_
extern uint8_t I2C_REGISTERS[10];
extern I2C_HandleTypeDef hi2c1;
#endif /* INC_I2C_SLAVE_H_ */
i2c_slave.c
#include "main.h"
#include "i2c_slave.h"
#include "string.h"
uint8_t I2C_REGISTERS[10] = {0,0,0,0,0,0,0,0,0,0};
extern I2C_HandleTypeDef hi2c1;
#define RxSIZE 11
uint8_t RxData[RxSIZE];
uint8_t rxcount=0;
uint8_t txcount=0;
uint8_t startPosition = 0;
uint8_t bytesRrecvd = 0;
uint8_t bytesTransd = 0;
int process_data (void)
{
int startREG = RxData[0]; // get the register address
int numREG = bytesRrecvd; // Get the number of registers
int endREG = startREG + numREG -1; // calculate the end register
if (endREG>9) // There are a total of 10 registers (0-9)
{
// clear everything and return
memset(RxData,'\0',RxSIZE);
rxcount =0;
return 0;
}
int indx = 1; // set the indx to 1 in order to start reading from RxData[1]
for (int i=0; i<numREG; i++)
{
I2C_REGISTERS[startREG++] = RxData[indx++]; // Read the data from RxData and
save it in the I2C_REGISTERS
}
return 1; // success
}
void HAL_I2C_ListenCpltCallback(I2C_HandleTypeDef *hi2c)
{
HAL_I2C_EnableListen_IT(hi2c);
}
void HAL_I2C_AddrCallback(I2C_HandleTypeDef *hi2c, uint8_t TransferDirection, uint16_t
AddrMatchCode)
{
if (TransferDirection == I2C_DIRECTION_TRANSMIT) // if the master wants to transmit the
data
{
RxData[0] = 0; // reset the RxData[0] to clear any residue address from previous call
rxcount =0;
HAL_I2C_Slave_Seq_Receive_IT(hi2c, RxData+rxcount, 1, I2C_FIRST_FRAME);
}
else
{
txcount = 0;
startPosition = RxData[0];
RxData[0] = 0; // Reset the start register as we have already copied it
HAL_I2C_Slave_Seq_Transmit_IT(hi2c, I2C_REGISTERS+startPosition+txcount, 1,
I2C_FIRST_FRAME);
}
}
void HAL_I2C_SlaveTxCpltCallback(I2C_HandleTypeDef *hi2c)
{
txcount++;
HAL_I2C_Slave_Seq_Transmit_IT(hi2c, I2C_REGISTERS+startPosition+txcount, 1,
I2C_NEXT_FRAME);
}
void HAL_I2C_SlaveRxCpltCallback(I2C_HandleTypeDef *hi2c)
{
rxcount++;
if (rxcount < RxSIZE)
{
if (rxcount == RxSIZE-1)
{
HAL_I2C_Slave_Seq_Receive_IT(hi2c, RxData+rxcount, 1,
I2C_LAST_FRAME);
}
else
{
HAL_I2C_Slave_Seq_Receive_IT(hi2c, RxData+rxcount, 1,
I2C_NEXT_FRAME);
}
}
if (rxcount == RxSIZE)
{
process_data();
}
}
void HAL_I2C_ErrorCallback(I2C_HandleTypeDef *hi2c)
{
uint32_t errorcode = HAL_I2C_GetError(hi2c);
if (errorcode == 4) // AF error
{
if (txcount == 0) // error is while slave is receiving
{
bytesRrecvd = rxcount-1; // the first byte is the register address
rxcount = 0; // Reset the rxcount for the next operation
process_data();
}
else // error while slave is transmitting
{
bytesTransd = txcount-1; // the txcount is 1 higher than the actual data
transmitted
txcount = 0; // Reset the txcount for the next operation
}
}
/* BERR Error commonly occurs during the Direction switch
* Here we the software reset bit is set by the HAL error handler
* Before resetting this bit, we make sure the I2C lines are released and the bus is free
* I am simply reinitializing the I2C to do so
*/
else if (errorcode == 1) // BERR Error
{
HAL_I2C_DeInit(hi2c);
HAL_I2C_Init(hi2c);
memset(RxData,'\0',RxSIZE); // reset the Rx buffer
rxcount =0; // reset the count
}
HAL_I2C_EnableListen_IT(hi2c);
}