I faced a problem in reading EEPROM 24LC512 using I2C STM32F103C8T6. Whenever I tried to use i2cMasterTransmitTimeout() and it hang at ch.dbg.panic_msg = reason when I commented the function and it works fine. I tested EEPROM on Arduino and it works just fine so it's not EEPROM problem. Debug info is showed as following.
Source code (Please let me know if I should skip irrelevant code next time for easier reading)
Code: Select all
#include "ch.h"
#include "hal.h"
#include "chprintf.h"
#include "onewire.h"
static int32_t ftomod(float value);
static uint32_t ftodp(float value);
void setRTCAlarmPeriod(uint32_t seconds);
void powerStandby(void);
#define RTC_ALARM_PERIOD 10
RTCDateTime timespec;
RTCAlarm alarmspec;
#define ADC_GRP1_NUM_CHANNELS 1
#define ADC_GRP1_BUF_DEPTH 8
#define EEPROM_ADD 0x50
static BaseSequentialStream* chp = (BaseSequentialStream*)&SD2;
static adcsample_t samples1[ADC_GRP1_NUM_CHANNELS * ADC_GRP1_BUF_DEPTH];
static float mean;
/*
* ADC conversion group.
* Mode: Linear buffer, 8 samples of 1 channel, SW triggered.
* Channels: IN10.
*/
static const ADCConversionGroup adcgrpcfg1 = {
FALSE,
ADC_GRP1_NUM_CHANNELS,
NULL,
NULL,
0, 0, /* CR1, CR2 */
0, /* SMPR1 */
ADC_SMPR2_SMP_AN8(ADC_SAMPLE_1P5),
ADC_SQR1_NUM_CH(ADC_GRP1_NUM_CHANNELS),
0, /* SQR2 */
ADC_SQR3_SQ1_N(ADC_CHANNEL_IN8)
};
/*
* I2C1 config.
*/
static const I2CConfig i2cfg1 = {
OPMODE_I2C,
400000,
FAST_DUTY_CYCLE_2,
};
i2cflags_t i2cflags = 0;
static uint8_t tx_data[4];
static uint8_t rx_data[4];
static systime_t calc_timeout(size_t bytes, uint32_t clock) {
const uint32_t bitsinbyte = 10;
uint32_t tmo_ms;
tmo_ms = ((bytes + 1) * bitsinbyte * 1000);
tmo_ms /= clock;
tmo_ms += 10; /* some additional milliseconds to be safer */
return MS2ST(tmo_ms);
}
static THD_WORKING_AREA(waEEPROM, 128);
static THD_FUNCTION(Thread_EEPROM, arg) {
msg_t status = MSG_OK;
systime_t tmo = calc_timeout(3, 100000);
(void)arg;
chRegSetThreadName("EEPROM");
while(true) {
chprintf(chp, "EEPROM\r\n");
i2cAcquireBus(&I2CD1);\
tx_data[0] = 0x00;
tx_data[1] = 0x00;
//status = i2cMasterReceiveTimeout(&I2CD1, EEPROM_ADD, rx_data, 2, tmo);
status = i2cMasterTransmitTimeout(&I2CD1, EEPROM_ADD, tx_data, 2, rx_data, 2, tmo);
if (MSG_OK != status)
i2cflags = i2cGetErrors(&I2CD1);
//osalDbgCheck(MSG_OK == status);
i2cReleaseBus(&I2CD1);
chprintf(chp, "Status: %d, Data: %d, %d\r\n", status, rx_data[0], rx_data[1]);
chThdSleepSeconds(1);
}
}
/*
* Light sensor measurement thread.
*/
static THD_WORKING_AREA(waLightSensor, 128);
static THD_FUNCTION(Thread_LightSensor, arg) {
uint8_t i;
(void)arg;
chRegSetThreadName("lightsensor");
// Convert ADC
adcConvert(&ADCD1, &adcgrpcfg1, samples1, ADC_GRP1_BUF_DEPTH);
// Turn off ADC
adcStop(&ADCD1);
// Calculate mean value
mean = 0;
for (i = 0; i < ADC_GRP1_NUM_CHANNELS * ADC_GRP1_BUF_DEPTH; i++) {
mean += samples1[i];
}
mean = (float)(mean / (ADC_GRP1_NUM_CHANNELS * ADC_GRP1_BUF_DEPTH));
//last_value = (float)(mean * 3.218 / 4095);
//sensor_value = (float)(97500 * last_value / (3.218 - last_value));
chprintf(chp, "Mean: %d.%03d\n\r", ftomod(mean), ftodp(mean));
//chprintf(chp, "Voltage output: %d.%03dV\n\r", ftomod(last_value), ftodp(last_value));
//chprintf(chp, "Resistant: %d\n\r", ftomod(sensor_value));
//chThdSleepSeconds(RTC_ALARM_PERIOD);
//chprintf(chp, "\033[2J\033[1;1H");
}
/*
* DS18B20 thread
*/
static THD_WORKING_AREA(waDS18B20, 128);
static THD_FUNCTION(Thread_DS18B20, arg) {
float temperature = 0.0;
(void)arg;
chRegSetThreadName("ds18b20");
// Read temperature
temperature = oneWireReadTemperature();
// Stop gpt
oneWireStop();
chprintf(chp, "Temperature: %d.%01d\n\r", ftomod(temperature), ftodp(temperature));
//chThdSleepSeconds(RTC_ALARM_PERIOD);
}
int main(void) {
halInit();
chSysInit();
// Serial UART2
sdStart(&SD2, NULL);
chprintf(chp, "iSensor\r\n");
// MOSFET drive
//palSetPadMode(GPIOB, 11, PAL_MODE_OUTPUT_OPENDRAIN);
//palSetPad(GPIOB, 11);
//chThdSleepSeconds(1);
// Onewire for DS18B20
//oneWireInit();
// DS18B20 sensor thread
//chThdCreateStatic(waDS18B20, sizeof(waDS18B20), NORMALPRIO + 2, Thread_DS18B20, NULL);
// Setting up analog inputs
//palSetPadMode(GPIOB, 0, PAL_MODE_INPUT_ANALOG);
// Activates the ADC1 driver and the temperature sensor.
//adcStart(&ADCD1, NULL);
// Light sensor thread
//chThdCreateStatic(waLightSensor, sizeof(waLightSensor), NORMALPRIO + 2, Thread_LightSensor, NULL);
// I2C
palSetPadMode(GPIOB, 6, PAL_MODE_STM32_ALTERNATE_OPENDRAIN); /* SCL */
palSetPadMode(GPIOB, 7, PAL_MODE_STM32_ALTERNATE_OPENDRAIN); /* SDA */
i2cStart(&I2CD1, &i2cfg1);
chThdCreateStatic(waEEPROM, sizeof(waEEPROM), NORMALPRIO + 1, Thread_EEPROM, NULL);
setRTCAlarmPeriod(RTC_ALARM_PERIOD);
while(true) {
chprintf(chp, "SLEEP...\r\n");
chThdSleepSeconds(3);
//powerStandby();
}
return 0;
}
void setRTCAlarmPeriod(uint32_t seconds) {
uint32_t tv_sec;
/* compile ability test */
rtcGetTime(&RTCD1, ×pec);
/* set alarm in near future */
rtcSTM32GetSecMsec(&RTCD1, &tv_sec, NULL);
alarmspec.tv_sec = tv_sec + seconds;
rtcSetAlarm(&RTCD1, 0, &alarmspec);
}
void powerStandby(void) {
//palClearPad(GPIOB, 11);
// Turn off Serial
sdStop(&SD2);
palSetGroupMode(GPIOA, 0xFFFF, 0, PAL_MODE_INPUT_ANALOG);
palSetGroupMode(GPIOB, 0xFFFF, 0, PAL_MODE_INPUT_ANALOG);
palSetGroupMode(GPIOC, 0xFFFF, 0, PAL_MODE_INPUT_ANALOG);
rccDisableAHB(RCC_AHBENR_DMA1EN | RCC_AHBENR_SRAMEN | RCC_AHBENR_FLITFEN | \
RCC_AHBENR_CRCEN, lp);
rccDisableAPB2(RCC_APB2ENR_AFIOEN | RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPBEN | \
RCC_APB2ENR_IOPCEN | RCC_APB2ENR_ADC1EN | RCC_APB2ENR_ADC2EN | \
RCC_APB2ENR_TIM1EN | RCC_APB2ENR_SPI1EN | RCC_APB2ENR_USART1EN, lp);
rccDisableAPB1(RCC_APB1ENR_TIM2EN | RCC_APB1ENR_TIM3EN | RCC_APB1ENR_WWDGEN | \
RCC_APB1ENR_USART2EN | RCC_APB1ENR_I2C1EN | RCC_APB1ENR_CAN1EN | \
RCC_APB1ENR_USBEN, lp);
chSysLock();
PWR->CR |= PWR_CR_CWUF;
//PWR->CR |= PWR_CR_PDDS | PWR_CR_LPDS;
PWR->CR |= PWR_CR_PDDS;
SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
__WFI();
}
/*
* Retrieve the integer part of value
*/
static int32_t ftomod(float value){
if (value >= 0)
return (int32_t) value;
else
return (int32_t) -1 * value;
}
/*
* Retrieve the decimal part of value
*/
static uint32_t ftodp(float value) {
if (value >= 0)
return (uint32_t) ((value - ftomod (value)) * 1000);
else
return (uint32_t) ((-value - ftomod (value)) * 1000);
}