STM32F4 как ведомый I2C. Почему «void I2C1_ER_IRQHandler (void)» выполняется после «HAL_I2C_Slave_Transmit_DMA»? - PullRequest
1 голос
/ 11 апреля 2019

Я использую шину I2C в качестве режима SLAVE в STM32F411RE. Мастер - доска Arduino.

Конфигурация работает хорошо, потому что я вижу мастер-сериал (arduino) и STstudio (STM32F411), что все кадры в порядке и через осциллограф.

Я заметил, что функция I2C1_ER_IRQHandler запускается каждый раз, когда ведомое устройство заканчивает свою передачу TX (ведущее устройство принимает это преобразование и завершает работу с NACK и STOP BIT). По следующей ссылке:

https://drive.google.com/file/d/1-W5Z2nsvLNj6PE1TT9eDCDdYvFpnis8g/view?usp=sharing https://drive.google.com/file/d/14JkeAw2If3v0A71V9-KQasH9rK3PRm3H/view?usp=sharing https://drive.google.com/file/d/1Te2F8aNnvkqUSnfRK5UOO-qKabLXXv1D/view?usp=sharing

вы можете загружать изображения, вы можете видеть сигнал SDA и GPIO PIN 2, который переключается в функции I2C1_ER_IRQHandler. ¿Может быть связано с тем, что Slave (stm32) получает NACK в конце передачи? смотреть фотографии

Основные функции и вызовы SLAVE:

#define BUFFERSIZE_RX      0x03    // Master sends 3 bytes
#define BUFFERSIZE_TX      0x04    //Master is waiting for 4 bytes

uint8_t aRxBuffer[BUFFERSIZE_RX];
uint8_t aTxBuffer[BUFFERSIZE_TX];

int main(void)
{
…uC INITIALIZATION

    if(HAL_I2C_Slave_Receive_DMA(&hi2c1, (uint8_t *)aRxBuffer, BUFFERSIZE_RX) != HAL_OK)
    {
        Error_Handler();
    }
    while (1)
    {}
}

void HAL_I2C_SlaveTxCpltCallback(I2C_HandleTypeDef *hi2c)
{
    if(HAL_I2C_GetState(&hi2c1) == HAL_I2C_STATE_READY)
    {
        if(HAL_I2C_Slave_Receive_DMA(&hi2c1, (uint8_t *)aRxBuffer, BUFFERSIZE_RX) != HAL_OK)
        {
            Error_Handler();
        }
    }
}

void HAL_I2C_SlaveRxCpltCallback(I2C_HandleTypeDef *hi2c)      
{
    if(HAL_I2C_GetState(&hi2c1) == HAL_I2C_STATE_READY)
    {
        if(HAL_I2C_Slave_Transmit_DMA(&hi2c1, (uint8_t*)aTxBuffer, BUFFERSIZE_TX)!= HAL_OK)
        {
           Error_Handler();
        }
    }
}

void HAL_I2C_ErrorCallback(I2C_HandleTypeDef *hi2c)
{
    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_3, GPIO_PIN_SET);
}

void I2C1_ER_IRQHandler(void)
{
 HAL_I2C_ER_IRQHandler(&hi2c1);
 HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_2);
}

Конфигурация I2C и DMA в качестве примеров STM32Cube_FW_F4_V1.24.0, но, если они вам нужны, я также могу отправить их.

Arduino Master отправляет только следующие функции:

void loop()
{       
    Wire.beginTransmission(address);
    Wire.write((uint8_t)M_TX_1);
    Wire.write((uint8_t)M_TX_2);
    Wire.write((uint8_t)M_TX_3);
    Wire.endTransmission();
    delay(1);
    Wire.requestFrom(address, (uint8_t)4);
    M_RX_1 = Wire.read();
    M_RX_2 = Wire.read();      
    M_RX_3 = Wire.read();
    M_RX_4 = Wire.read();
… Serial prints and so on…     
}

Я проверил I2C в режиме прерывания, и происходит то же самое ... связь работает, но всегда вызывается I2C1_ER_IRQHandler.

Я полностью потерян, любая помощь или комментарий действительно ценны !!!

Извините за длинный пост.

P.D. HAL_I2C_ErrorCallback никогда не вызывался, поэтому я полагаю, что все в порядке.

С уважением.

Alejandro

PD2: конфигурация SPI GPIO и DMA:

static void MX_I2C1_Init(void)
{
    hi2c1.Instance = I2C1;
    hi2c1.Init.ClockSpeed = 100000;
    //hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2;
    hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_16_9;  // Modificacion
    hi2c1.Init.OwnAddress1 = SLAVEADDRESS << 1; // Modificacion
    hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
    hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
    hi2c1.Init.OwnAddress2 = 0;
    //hi2c1.Init.OwnAddress2 = 0x06;        // Modificacion
    hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
    hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
    if (HAL_I2C_Init(&hi2c1) != HAL_OK)
    {
    Error_Handler();
    }
}

static void MX_DMA_Init(void) 
{
    __HAL_RCC_DMA1_CLK_ENABLE();

    HAL_NVIC_SetPriority(DMA1_Stream0_IRQn, 0, 1);
    HAL_NVIC_EnableIRQ(DMA1_Stream0_IRQn);
    HAL_NVIC_SetPriority(DMA1_Stream1_IRQn, 0, 2);
    HAL_NVIC_EnableIRQ(DMA1_Stream1_IRQn);
}

void HAL_I2C_MspInit(I2C_HandleTypeDef* hi2c)
{
  GPIO_InitTypeDef GPIO_InitStruct = {0};
  if(hi2c->Instance==I2C1)
  {
    __HAL_RCC_GPIOB_CLK_ENABLE();

    GPIO_InitStruct.Pin = GPIO_PIN_6|GPIO_PIN_7;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
    GPIO_InitStruct.Pull = GPIO_PULLUP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF4_I2C1;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

    __HAL_RCC_I2C1_CLK_ENABLE();

    hdma_i2c1_rx.Instance = DMA1_Stream0;
    hdma_i2c1_rx.Init.Channel = DMA_CHANNEL_1;
    hdma_i2c1_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
    hdma_i2c1_rx.Init.PeriphInc = DMA_PINC_DISABLE;
    hdma_i2c1_rx.Init.MemInc = DMA_MINC_ENABLE;
    hdma_i2c1_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
    hdma_i2c1_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
    hdma_i2c1_rx.Init.Mode = DMA_NORMAL;
    hdma_i2c1_rx.Init.Priority = DMA_PRIORITY_LOW;
    hdma_i2c1_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
    hdma_i2c1_rx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;  
    hdma_i2c1_rx.Init.MemBurst = DMA_MBURST_INC4;               
    hdma_i2c1_rx.Init.PeriphBurst = DMA_PBURST_INC4;    
    if (HAL_DMA_Init(&hdma_i2c1_rx) != HAL_OK)
    {
        Error_Handler();
    }
    __HAL_LINKDMA(hi2c,hdmarx,hdma_i2c1_rx);

    hdma_i2c1_tx.Instance = DMA1_Stream1;
    hdma_i2c1_tx.Init.Channel = DMA_CHANNEL_0;
    hdma_i2c1_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
    hdma_i2c1_tx.Init.PeriphInc = DMA_PINC_DISABLE;
    hdma_i2c1_tx.Init.MemInc = DMA_MINC_ENABLE;
    hdma_i2c1_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
    hdma_i2c1_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
    hdma_i2c1_tx.Init.Mode = DMA_NORMAL;
    hdma_i2c1_tx.Init.Priority = DMA_PRIORITY_HIGH;
    hdma_i2c1_tx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
    hdma_i2c1_tx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;              
    hdma_i2c1_tx.Init.MemBurst = DMA_MBURST_INC4;           
    hdma_i2c1_tx.Init.PeriphBurst = DMA_PBURST_INC4;
    if (HAL_DMA_Init(&hdma_i2c1_tx) != HAL_OK)
    {
        Error_Handler();
    }

    __HAL_LINKDMA(hi2c,hdmatx,hdma_i2c1_tx);

    HAL_NVIC_SetPriority(I2C1_EV_IRQn, 0, 3);
    HAL_NVIC_EnableIRQ(I2C1_EV_IRQn);
    HAL_NVIC_SetPriority(I2C1_ER_IRQn, 0, 2);
    HAL_NVIC_EnableIRQ(I2C1_ER_IRQn);
  }
}

1 Ответ

1 голос
/ 11 апреля 2019

Для начала, возможно ли, что это событие IRQ (EV), указывающее, что ведомое устройство завершило передачу данных и не является ошибкой IRQ?Возможно, вы настроили это так, чтобы показать, что ведомое устройство выполняет передачу данных по шине.

Если это не так, определенно лучше взгляните на стандарт связи I2C.В вашем случае NACK просто указывает на остановку передачи все вместе от мастера, или это может означать, что передача не удалась, но если вы говорите, что все кадры успешны, то это определенно условие конца передачи.При этом важно знать, как все это было настроено.Я бы проверил последовательность инициализации I2C на F4 и убедился, что она соответствует тому, что ожидается от Arduino.Это должно быть что-то вроде этого.

  1. Настройка связанных часов с I2C и GPIO
  2. Отображение GPIO
  3. Включение служб прерываний, необходимых через Nested Vectored Interrupt Controller(NVIC)
  4. Установите настройки I2C на желаемое кадрирование
  5. Включите периферию I2C и прерывания

Эти шаги позволят вам убедиться, что выприкрывая свою землю здесь.

Теперь вы также должны убедиться, что у вас включены правильные функции, если вы также используете DMA с I2C.F4 выполняет некоторую проверку ошибок пакета после окончания каждого сообщения.У вас включен PEC?Если это так, убедитесь, что нет никаких причин, вызывающих срабатывание прерывания IRQ.

У вас также есть флаги событий для чтения в отладчике, чтобы увидеть, какая ошибка конкретно вызвала строку ошибки I2C IRQ.Согласно справочному руководству по STMF4, флаги событий для генерации прерывания:

0: Error interrupt disabled
1: Error interrupt enabled
This interrupt is generated when:
– BERR = 1
– ARLO = 1
– AF = 1
– OVR = 1
– PECERR = 1
– TIMEOUT = 1
– SMBALERT = 1

Хотя вы упомянули, что функция обратного вызова с ошибкой не была активна, поэтому они могут отсутствовать.

И наконец, просто для безопасности убедитесь, что линия IRQ не используется где-либо еще в программном обеспечении.может случиться так, что линия контролируется чем-то другим и поднимается высоко, вызывая функцию обработчика IRQ.Это маловероятно, если вы опубликовали только один код, но стоит подумать.

...