Возвращение в хобби, новый проект, понимай как хочешь...

В общем, после некоторого забвения, решил поиграться с F4BY и сделать проект с нуля - очень простой (можно сказать для чайников), который в принципе мог бы быть уроком для самого простого вхождения в STM32, но к сожалению не получилось 😦

Если кому интересен сам процесс могу рассказать с картинками и видео, но позже - когда решу проблему…
И так: взят STM32CUBE MX (генератор кода для STM - пока без ссылок - всё можно взять у них на сайте ST), там же System Workbench for STM32 ( бесплатная среда, требуется регистрация для скачивания, ссыль так же есть на сайте ST) собственно F4BY (хотя неважно - любой контроллер STM32 - суть не в этом).

Короче, в STM32CUBE MX конфигурируешь то что хочешь получить от процессора(создаёшь хардварный абстрактный слой для нужного проца, в System Workbench for STM32 просто дописываешь то, что тебе нужно…

Проблема: не смог прочитать компас HMC5883/5983 по шине i2c - что говорит шина - return HAL_BUSY - занято, “перезвоните попозже”. Ладно, было принято решение “прозвонить” шину по адресам (какие есть) - ответ получаю стабильно - 2 устройства компас и баро, но как только пытаюсь читать компас получаю пустые данные (так для понятия картины - настраивать и читать его я умею - это частный случай), перепробовал кучу вариантов работы с i2c в данном хале, примеры:

void HMC5883L_initialize() {

    HAL_I2C_Mem_Write(&hi2c2, HMC5883l_ADDRESS, 0x00 , 1, &RegSettingA , 1, 100);
    HAL_I2C_Mem_Write(&hi2c2, HMC5883l_ADDRESS, 0x01 , 1, &RegSettingB , 1, 100);
    HAL_I2C_Mem_Write(&hi2c2, HMC5883l_ADDRESS, 0x02 , 1, &RegSettingMR , 1, 100);
}


void HMC5883LRead(int16_t *destination) {
    HAL_I2C_Mem_Read(&hi2c2,HMC5883l_ADDRESS,HMC5883l_ADD_DATAX_MSB_MULTI, 1, buffer, 6, 100);

    destination[0] = (((int16_t)buffer[0]) << 8) | buffer[1];
    destination[1] = (((int16_t)buffer[4]) << 8) | buffer[5];
    destination[2] = (((int16_t)buffer[2]) << 8) | buffer[3];
}

или

void HMC5883L_initialize() {
     buff[0] = HMC5883L_RA_CONFIG_A;
     buff[1] = HMC5883l_Enable_A;
     HAL_I2C_Master_Transmit(&hi2c2, (uint16_t)HMC5883l_ADDRESS, buff, 2, 100);
     HAL_Delay (100);
     buff[0] = HMC5883L_RA_CONFIG_B;
     buff[1] = HMC5883l_Enable_B;
     HAL_I2C_Master_Transmit(&hi2c2, (uint16_t)HMC5883l_ADDRESS,  buff, 2, 100);
     HAL_Delay (100);
     buff[0] = HMC5883L_RA_MODE;
     buff[1] = HMC5883l_MR;
     HAL_I2C_Master_Transmit(&hi2c2, (uint16_t)HMC5883l_ADDRESS, buff, 2, 100);
     HAL_Delay (100);
    }

void HMC5883LRead(int16_t *destination) {
     buff[0] = HMC5883L_RA_DATAX_H;
     HAL_I2C_Master_Transmit(&hi2c2,(uint16_t) HMC5883l_ADDRESS,  buff, 1, 100);

     HAL_I2C_Master_Receive(&hi2c2, (uint16_t)HMC5883l_ADDRESS, &buffer[0], 6, 100);

    destination[0] = (((int16_t)buffer[0]) << 8) | buffer[1];
    destination[1] = (((int16_t)buffer[4]) << 8) | buffer[5];
    destination[2] = (((int16_t)buffer[2]) << 8) | buffer[3];
}

короче - как бы не старался - при записи и/или чтении всё одно - “занято”, ладно, есть же умный гугель! Ога или Аго, в либах есть беда: не сбрасывается флаг аналогового фильтра на лапах, но ведь адреса то мы пробиваем??? ладно у СТ есть костыль под это дело цельных 15 шагов (как прям для буржуйских алкоголиков) - применим:

/**
    1. Disable the I2C peripheral by clearing the PE bit in I2Cx_CR1 register.
    2. Configure the SCL and SDA I/Os as General Purpose Output Open-Drain, High level
    (Write 1 to GPIOx_ODR).
    3. Check SCL and SDA High level in GPIOx_IDR.
    4. Configure the SDA I/O as General Purpose Output Open-Drain, Low level (Write 0 to
    GPIOx_ODR).
    5. Check SDA Low level in GPIOx_IDR.
    6. Configure the SCL I/O as General Purpose Output Open-Drain, Low level (Write 0 to
    GPIOx_ODR).
    7. Check SCL Low level in GPIOx_IDR.
    8. Configure the SCL I/O as General Purpose Output Open-Drain, High level (Write 1 to
    GPIOx_ODR).
    9. Check SCL High level in GPIOx_IDR.
    10. Configure the SDA I/O as General Purpose Output Open-Drain , High level (Write 1 to
    GPIOx_ODR).
    11. Check SDA High level in GPIOx_IDR.
    12. Configure the SCL and SDA I/Os as Alternate function Open-Drain.
    13. Set SWRST bit in I2Cx_CR1 register.
    14. Clear SWRST bit in I2Cx_CR1 register.
    15. Enable the I2C peripheral by setting the PE bit in I2Cx_CR1 register.
    **/
    void HAL_I2C_ClearBusyFlagErrata_2_14_7(I2C_HandleTypeDef *hi2c) {

        static uint8_t resetTried = 0;
        if (resetTried == 1) {
            return ;
        }
        GPIO_InitTypeDef GPIO_InitStruct;

        // 1
        __HAL_I2C_DISABLE(hi2c);

        // 2
        GPIO_InitStruct.Pin = GPIO_PIN_10|GPIO_PIN_11;
        GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
        GPIO_InitStruct.Pull = GPIO_PULLUP;
        GPIO_InitStruct.Speed = GPIO_SPEED_FAST;
        HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

        HAL_GPIO_WRITE_ODR(GPIOB, GPIO_PIN_10);
        HAL_GPIO_WRITE_ODR(GPIOB, GPIO_PIN_11);

        // 3
        GPIO_PinState pinState;
        if (HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_10) == GPIO_PIN_RESET) {
            for(;;){}
        }
        if (HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_11) == GPIO_PIN_RESET) {
            for(;;){}
        }

        // 4
        GPIO_InitStruct.Pin = GPIO_PIN_10;
        HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

        HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_10);

        // 5
        if (HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_10) == GPIO_PIN_SET) {
            for(;;){}
        }

        // 6
        GPIO_InitStruct.Pin = GPIO_PIN_11;
        HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

        HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_11);

        // 7
        if (HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_11) == GPIO_PIN_SET) {
            for(;;){}
        }

        // 8
        GPIO_InitStruct.Pin = GPIO_PIN_10;
        HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

        HAL_GPIO_WRITE_ODR(GPIOB, GPIO_PIN_10);

        // 9
        if (HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_10) == GPIO_PIN_RESET) {
            for(;;){}
        }

        // 10
        GPIO_InitStruct.Pin = GPIO_PIN_11;
        HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

        HAL_GPIO_WRITE_ODR(GPIOB, GPIO_PIN_11);

        // 11
        if (HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_11) == GPIO_PIN_RESET) {
            for(;;){}
        }

        // 12
        GPIO_InitStruct.Pin = GPIO_PIN_10|GPIO_PIN_11;
        GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
        GPIO_InitStruct.Alternate = GPIO_AF4_I2C2;
        HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

       // 13
       hi2c->Instance->CR1 |= I2C_CR1_SWRST;

       // 14
       hi2c->Instance->CR1 ^= I2C_CR1_SWRST;

       // 15
       __HAL_I2C_ENABLE(hi2c);

       resetTried = 1;
    }

    void HAL_GPIO_WRITE_ODR(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
    {
      /* Check the parameters */
      assert_param(IS_GPIO_PIN(GPIO_Pin));

      GPIOx->ODR |= GPIO_Pin;
    }

 

Фиг вам (национальное индейское жилище) - занято и всё тут, тестером тыкал - да шина висит в полуподвешеном состоянии, мысли кончились, вот решил написать…
Короче решил бросить эту идею и написать всё на
STM32 Standard Peripheral Libraries

по крайней мере все драйвера у меня (кроме усб - но это решаемо) написаны и работают, конечно это сложнее для начинающих, но мне проще - я с ними уже работал, и уже воевал с этой шиной на F4 - в тот раз я победил)))

  • 1438
Comments
RW9UAO

там с уарт ДМА такая же точно придурь. висит в состоянии “занято”. лечилось исправлением в каком-то из обработчиков прерывания. уже не помню каком.
я обошел примерно как и ты - набросал свой драйвер =)

alexeykozin

Привет Серега, прикольно.
а чего втихаря? не поделился ссылкой с коллегами то?
продолжение будет?