I have two i2c devices. Both alone work well, but when I read from one, and then write to the other, the second one is not an ancknowledging - i2c

I have two devices MPU6050 and EEPROM 24C256. I can write and read from both alone. But when I try to read from MPU6050 and than write data to EEPROM in the same session, the EEPROM does not respond. I am using mbed OS libraries. And my question is.. Is it library, code or hardware problem?
MPU6050 read sequence:
enter image description here
EEPROM write page sequance:
enter image description here
//CODE
const char imuAddress = 0x68<<1;
const char imuDataAddress = 0x3B;
const char eepAddress = 0xA0;
const char data[3] = {1.1, 2.2, 3.3};
char acc[3];
//reading acceleration data from IMU
while(true){
i2c.start();
if(i2c.write(imuAddress) != 1){
i2c.stop();
continue;
}
if(i2c.write(imuDataAddress) != 1){
i2c.stop();
continue;
}
i2c.start();
if(i2c.write(imuAddress | 0x01) != 1){
i2c.stop();
continue;
}
for (int i = 0; i < 2; i++){
i2c.read(1); //read and respond ACK to continue
}
i2c.read(0); //read and respond NACK to stop reading
i2c.stop();
break;
}
//write data to EEPROM
while(true){
i2c.start();
if(i2c.write(eepAddress) != 1){ //here is the problem (EEPROM does not respond)
i2c.stop();
continue;
}
if(i2c.write(0x00) != 1){
i2c.stop();
continue;
}
if(i2c.write(0x00) != 1){
i2c.stop();
continue;
}
bool ack = true;
for(int i = 0; i < 3; i++){
if(i2c.write(data[i]) != 1){
i2c.stop();
ack = false;
break;
}
}
if (ack == true){
i2c.stop();
break;
}
}

I have a couple initial thoughts, but do you have access to an oscilloscope? It is odd that each one works individually. This makes me think that it may be an issue between the transition. (Possibly try a delay between each one? Also, possibly remove the stops in the initial read as they aren't necessary)
I think the best way to figure this out is to post a scope trace of the messaging for each one running individually and a trace of them running back to back.

Related

STM32 HAL I2C IsDeviceReady (I2C detect) device Plug out and Plug in again - No Device found

I am implementing I2C detect feature in my stm32 ptoject, but I came across a problem. I am using stm32F103C8T6 (BluePill) and Nucloe-144 board which shows the same behavior.
The problem:
When I'm running i2cdetect function in loop with some delay (3-5 sec) I can see the address of my i2c slave device (e.g. MCP23008), but if I plug connector out (4pin connector = gnd,scl,sda,vcc at the same time) and then plug it in again I can't see the device until I reset I2C master (bluepill or nucleo).
Note: I can plug out and plug in again i2c slaves as many times as I want and I will see them every time I use the i2cdetect command from i2ctools with my raspberry pi 3 model B.
My i2cmaster code implementing i2cdetect:
int main(void)
{
while (1)
{
i2c_detect();
HAL_Delay(5000);
}
}
void i2c_detect(void)
{
char str[56]; uint8_t len=0; uint8_t devices = 0, ret;
extern I2C_HandleTypeDef hi2c1;
CDC_Transmit_FS((uint8_t*)"\r\nSearching for I2C devices on the bus...\r\n", strlen("\r\nSearching for I2C devices on the bus...\r\n"));
for (uint8_t i = 1; i < 128; i++)
{
ret = HAL_I2C_IsDeviceReady(&hi2c1, (uint8_t)(i<<1), 3, 10);
if (ret != HAL_OK) /* No ACK Received At That Address */
{
while (USBD_BUSY == CDC_Transmit_FS((uint8_t*)" - ", strlen(" - ")));
}
else if (ret == HAL_OK)
{
len=sprintf(str,"0x%X",i);
while (USBD_BUSY == CDC_Transmit_FS((uint8_t*)str, len));
devices++;
}
}
/* Feedback of the total number of devices. */
if (devices == 0)
{
while (USBD_BUSY == CDC_Transmit_FS((uint8_t*)"\r\nNo device found.", strlen("\r\nNo device found.")));
}
else
{
len=sprintf(str,"\r\nTotal found devices: %d",devices);
while (USBD_BUSY == CDC_Transmit_FS((uint8_t*)str, len));
}
}
So, any thoughts why this happening? How can I implement behavior same to i2cdetect from i2ctools on Linux?

How can I change LED's brightness with PWM and USART in USART1_IRQHandler?

I am using STM32F4 discovery board and I am working on changing LED brightness and timer period using ADC and USART.
I use DMA to fetch ADC values, selected TIM4 for PWM and selected USART1 for USART. ADC, USART and PWM are working well so far, but USART1_IRQHandler() is not working as expected.
How can I adjust timer period and LED brightness with PWM and ADC in the following implementation of USART1_IRQHandler()?
void USART1_IRQHandler()
{
if (USART_GetITStatus(USART1, USART_IT_RXNE) )
{
delay(168000);
i = USART_ReceiveData(USART1);
if(i == '1'){
TIMOC_InitStruct.TIM_Pulse=pwm_value;
TIM_OC1Init(TIM4,&TIMOC_InitStruct);
TIM_OC1PreloadConfig(TIM4,TIM_OCPreload_Enable);
UARTSend("3 led aktif\r\n",sizeof("LED 4 ON\r\n"));
}
else if(i == '2')
{
TIMOC_InitStruct.TIM_Pulse=pwm_value;
TIM_OC1Init(TIM4,&TIMOC_InitStruct);
TIM_OC1PreloadConfig(TIM4,TIM_OCPreload_Enable);
TIMOC_InitStruct.TIM_Pulse=pwm_value;
TIM_OC2Init(TIM4,&TIMOC_InitStruct);
TIM_OC2PreloadConfig(TIM4,TIM_OCPreload_Enable);
UARTSend("2 led aktif\r\n",sizeof("LED 4 ON\r\n"));
}
else if(i == '4')
{
TIMOC_InitStruct.TIM_Pulse=pwm_value;
TIM_OC1Init(TIM4,&TIMOC_InitStruct);
TIM_OC1PreloadConfig(TIM4,TIM_OCPreload_Enable);
TIMOC_InitStruct.TIM_Pulse=pwm_value;
TIM_OC2Init(TIM4,&TIMOC_InitStruct);
TIM_OC2PreloadConfig(TIM4,TIM_OCPreload_Enable);
TIMOC_InitStruct.TIM_Pulse=pwm_value;
TIM_OC3Init(TIM4,&TIMOC_InitStruct);
TIM_OC3PreloadConfig(TIM4,TIM_OCPreload_Enable);
UARTSend("4 led aktif\r\n",sizeof("LED 4 ON\r\n"));
}
else if(i == '4')
{
TIMOC_InitStruct.TIM_Pulse=pwm_value;
TIM_OC1Init(TIM4,&TIMOC_InitStruct);
TIM_OC1PreloadConfig(TIM4,TIM_OCPreload_Enable);
TIMOC_InitStruct.TIM_Pulse=pwm_value;
TIM_OC2Init(TIM4,&TIMOC_InitStruct);
TIM_OC2PreloadConfig(TIM4,TIM_OCPreload_Enable);
TIMOC_InitStruct.TIM_Pulse=pwm_value;
TIM_OC3Init(TIM4,&TIMOC_InitStruct);
TIM_OC3PreloadConfig(TIM4,TIM_OCPreload_Enable);
TIMOC_InitStruct.TIM_Pulse=pwm_value;
TIM_OC4Init(TIM4,&TIMOC_InitStruct);
TIM_OC4PreloadConfig(TIM4,TIM_OCPreload_Enable);
UARTSend("4 led aktif\r\n",sizeof("LED 4 ON\r\n"));
}
else
{
Hello();
UARTSend("Please enter another number:\n",sizeof("Please enter another number:\n"));
}
} USART_ClearITPendingBit(USART1,USART_IT_RXNE);
}
About your USART1_IRQHandler, have you check if the interrupt is active with
__HAL_RCC_UART4_CLK_ENABLE();
HAL_NVIC_SetPriority(USART1_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(USART1_IRQn);
and if you enable it with this call
UART_Receive_IT( &huart1 );
I am using STM32Cube, repository V1.25.0.
Now, about your code inside the USART1_IRQHandler(), you could use shortcut to handle what you want to do. If I understand, you have 4 leds to control with the Timer4 and 4 channels.
The pulse is the Output Compare value (TIM4->CCR1 for channel 1). So, I would start the timer with a pulse equal to the Period (or zero. See note below).
From that point, if you want to change the brightness, you have just to change the pulse width with
__HAL_TIM_SET_COMPARE( htim4, TIM_CHANNEL_1, pwm_value);
or with
TIM4->CCR1 = pwm_value;
You could also disable any channel with
__HAL_TIM_DISABLE_IT( htim4, TIM_CHANNEL_1);
__HAL_TIM_ENABLE_IT( htim4, TIM_CHANNEL_1);
So, you get something like that
if(i == '1'){
TIM4->CCR1 = pwm_value;
} else if(i == '2') {
TIM4->CCR1 = pwm_value;
TIM4->CCR2 = pwm_value;
} ...
Note: I don't know how are connected your leds. If the led is connected to Vcc and the other end to the MPU pin, a LOW pulse will turn ON the led and HIGH pulse will turn it OFF.

STM32F4 Discovery

I have STM32F4 Discovery. I use IAR embedded Workbench. I am new to this kit. I want to measure distance. my code does not give an error. the distance is always zero. What could be the error? please help me . thanks everyone
#include "stm32f4_discovery.h"
#include "delay.h"
uint32_t Read_Distance(void);
void Init();
uint32_t distance ;
int main()
{
Init(); // initialisation de pin
SysTick_Init(); // pour pouvoire utiliser la fonction delay :)
while (1)
{
distance=Read_Distance();
delay_nms(100);
}
}
void Init()
{
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);
GPIO_InitTypeDef gpioStructure;
gpioStructure.GPIO_Pin = GPIO_Pin_10;
gpioStructure.GPIO_Mode = GPIO_Mode_OUT;
gpioStructure.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_Init(GPIOD, &gpioStructure);
gpioStructure.GPIO_Pin = GPIO_Pin_11;
gpioStructure.GPIO_Mode = GPIO_Mode_IN;
GPIO_Init(GPIOD, &gpioStructure);
}
//Les Pins pour le Test sont PD10 (Trig) et PD11(echo)
uint32_t Read_Distance(void)
{
__IO uint8_t flag=0;
__IO uint32_t disTime=0;
GPIO_SetBits(GPIOD,GPIO_Pin_10);
delay_nus(10);
GPIO_ResetBits(GPIOD,GPIO_Pin_10);
while(flag == 0)
{
while(GPIO_ReadInputDataBit(GPIOD,GPIO_Pin_11) == SET)
{
disTime++;
flag = 1;
}
}
return disTime;
}
Looks like you're using one of those ultrasonic distance measurement modules
Try this:
while(flag == 0)
{
disTime++;
if(GPIO_ReadInputDataBit(GPIOD,GPIO_Pin_11) == SET)
{
flag = 1;
}
}
You should use one of the hardware timers to get a more accurate time measurement.
Now I've had time to think more about it I remember now that you get a pulse sent back with a width proportional to the distance. I think this is the correct answer:
// Wait for pulse to start
while (GPIO_ReadInputDataBit(GPIOD,GPIO_Pin_11) == RESET)
{
NOP;
}
// Measure pulse width
while(flag == 0)
{
disTime++;
// Has pulse ended
if(GPIO_ReadInputDataBit(GPIOD,GPIO_Pin_11) == RESET)
{
flag = 1;
}
}
You may also want to tackle the case where the pulse is never received because this could will block forever.
If I understand correctly, D10 is wired to D11 and you want to check how long your signal remains high. If this is the case, you should increment a counter in timer interrupt handler when your pin is high and reset that counter variable once you've read it.

Stdout redirection not working in iOS without debugger

I am trying to redirect output so I can send it over the network. For some reason if you run the code while debugger attached it works perfectly. Once you start the application in normal way the code freezes on the read function and never returns. If someone has any pointers I will highly appreciate it.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^(void) {
static int pipePair[2];
if ( pipe(pipePair) != 0) {
return;
}
dup2(pipePair[1],STDOUT_FILENO);
while (true) {
char * buffer = calloc(sizeof(char), 1024);
ssize_t readCount = read(pipePair[0],buffer,1023);
if (readCount > 0) {
buffer[readCount] = 0;
NSString * log = [NSString stringWithCString:buffer encoding:NSUTF8StringEncoding];
//sent it over network
}
if (readCount == -1) {
return;
}
}
});
Apparently in iOS 5.1 writing to stdout was disallowed. http://spouliot.wordpress.com/2012/03/13/ios-5-1-vs-stdout/

Delay when using AudioQueueStart()

I am using the Audio Queue services to record audio on the iPhone. I am having a latency issue though when starting recording. Here is the code (approx):
OSStatus status = AudioQueueNewInput(
&recordState.dataFormat, // 1
AudioInputCallback, // 2
&recordState, // 3
CFRunLoopGetCurrent(), // 4
kCFRunLoopCommonModes, // 5
0, // 6
&recordState.queue); // 7
// create buffers
for(int i = 0; i < NUM_BUFFERS; i++)
{
if (status == 0)
status = AudioQueueAllocateBuffer(recordState.queue, BUFFER_SIZE, &recordState.buffers[i]);
}
DebugLog(#"Starting recording\n");
OSStatus status = 0;
for(int i = 0; i < NUM_BUFFERS; i++)
{
if (status == 0)
status = AudioQueueEnqueueBuffer(recordState.queue, recordState.buffers[i], 0, NULL);
}
DebugLog(#"Queued buffers\n");
if (status == 0)
{
// start audio queue
status = AudioQueueStart(recordState.queue, NULL);
}
DebugLog(#"Started recording, status = %d\n", status);
The log output looks like this:
2009-06-30 19:18:59.631 app[24887:20b] Starting recording
2009-06-30 19:18:59.828 app[24887:20b] Queued buffers
2009-06-30 19:19:00.849 app[24887:20b] Started recording, status = 0
Note the 1-second delay between the "Queued Buffers" message and 2nd "Starting recording" message. Any ideas how I can get rid of it, apart from starting recording as soon as I start my app?
BTW, the 1-second is pretty consistent in the Simulator and Device, and doesn't seem to be affected by number or size of buffers. Using good old mono 16-bit PCM.
Mike Tyson covers this in his blog.
However, if you're looking to quickly start recording you would do better to use a remote audio unit, or AVAudioEngine.