STM32CubeIDE (вопросы и ответы)

Где то ещё i2c код был, емли нужно - завтра найду.

Я такое не скоро написал бы :smiley:

Простой пример как использовать еще можно?

Выделенное опечатка или я чего-то не понимаю?

Что не так? То что не с нуля?

таймер 32 битный а диапазон как у 16 битного

опять в лужу?
прескалер от регистра перезагрузки не отличаешь?

Мне надо было для сохранения параметров.
Соответственно там всего две функции, запись параметра и чтение параметра.

void FLASH_write_param(unsigned short numParam, unsigned long paramValue);

unsigned long FLASH_read_param(unsigned short numParam);

Номер параметра 16 битный, само значение параметра 32х битное.

Я думал, что у 32х битного таймера шире диапазон прескалера. Хотя, наверное, просто «гоню» :smiley:

нее попутал просто :grinning:

а вот кто гонит, уже стало понятно!

NumParam - это адрес в странице флэша? Или что? Какой диапазон значений?

Номер параметра, это номер параметра, в адрес преобразуется само, не надо об этом думать.

Ну например это частота fm радиостанции в запрограммированных каналах, соответственно номер параметра это номер станции, значение параметра - частота.
Впрочем для радио я этот код и писал.

Ага, понял. Большое спасибо за разъяснение!

вот откопал код от 20 года, общее понимание работы с I2C через CMSIS можно почерпнуть.

Спойлер
//eeprom.h // модуль работы с EEPROM
#ifndef EEPROM_H
#define EEPROM_H

#define EEPROM_OWN_ADDRESS 0x50 // адрес I2C устройства - меняется пинами на 24LC64
#define EEPROM_PAGE_SIZE 32 // размер страницы для записи и чтения - из даташита на чип
#define EEPROM_START_TXT_DATA 4096 // начальный адрес для текстовых данных об MQTT сервере

void initEEPROMi2c(void); // инициализация шины I2C
void readEEPROMallDATA(void); // чтение из EEPROM 24LC64 данных о MQTT серверах

#endif  /* EEPROM_H */


//eeprom.c // модуль работы с EEPROM
#include "stm32f30x.h"
#include "dmfcomm.h"
#include "dmfuart.h"
#include <string.h>
#include "eeprom.h" // заголовочный файл со всеми константами

// http://arduino.ru/forum/otvlechennye-temy/programmirovanie-32-kh-razryadnykh-mk?page=20
unsigned char eeprom_buf[EEPROM_PAGE_SIZE]; // буфер чтения/записи страницы
#define CLEAR_EEPROM_BUF memset(eeprom_buf,0,EEPROM_PAGE_SIZE) // офистка буфера
unsigned long timerEEPROMpause; // таймер паузы для задержки между операциями

void delayEEPROM5msec(void) { // согласно даташиту, после любой записи в EEPROM необходимо подождать минимум 5 миллисекунд для следующей операции
    while ((current_millis - timerEEPROMpause) < 5UL); // если прошло 5 и более мсек - выходим
}

unsigned short getAddressFromNumBlock(const unsigned short numBlock) { // преобразует номер блока/страницы (так удобнее считать)
    return ((EEPROM_PAGE_SIZE * numBlock) + EEPROM_START_TXT_DATA); // возвращает физический адрес начала блока
}

unsigned char eeprom_read(const unsigned short address) { // чтение одного байте
    delayEEPROM5msec(); // ждем если вдруг что то в EEPROM записывали
    unsigned char temp=0; // временная переменная
    I2C1->CR2 = (2<<16) | (EEPROM_OWN_ADDRESS<<1); // адрес чипа со сдвигом влево и прописываем количество отправлемых байт NBYTES = 2
    while (!(I2C1->ISR & I2C_ISR_TXE) ); // ждем как шина освободится
    I2C1->TXDR = (unsigned char) (address>>8); /* Byte to send */ // отправлем в шину старший байт адреса EEPROM
    I2C1->CR2 |= I2C_CR2_START; /* Go */ // запускаем
    while (!(I2C1->ISR & I2C_ISR_TXIS) ); // ждем освобождения регистра данных
    I2C1->TXDR = (unsigned char) (address &0x00FF); /* Byte to send */ // отправляем в гину младший байт адреса EEPROM
    while (!(I2C1->ISR & I2C_ISR_TC) ){}; // ждем окончания отправки
    I2C1->CR2 = I2C_CR2_AUTOEND | (1<<16) | (EEPROM_OWN_ADDRESS<<1) | I2C_CR2_RD_WRN | I2C_CR2_NACK; // автоокончание приема,1 байт принять, адрес со сдвигом, режим приема, без флага ACK
        I2C1->CR2 |= I2C_CR2_START; /* Go */ // даем команду начала приема
        while (!(I2C1->ISR & I2C_ISR_RXNE) ){}; // ждем как прилетит байт
    temp = I2C1->RXDR; // читаем принятый байт из регистра
    return temp; // возвращаем его
}

void eeprom_write(const unsigned short address, const unsigned char data) { // запись одно байте в eeprom
    delayEEPROM5msec();
    I2C1->CR2 = I2C_CR2_AUTOEND | (3<<16) | (EEPROM_OWN_ADDRESS<<1);
    while (!(I2C1->ISR & I2C_ISR_TXE) ); /* Check Tx empty */
    I2C1->TXDR =(unsigned char) (address>>8); /* Byte to send */
    I2C1->CR2 |= I2C_CR2_START; /* Go */
    while (!(I2C1->ISR & I2C_ISR_TXIS) );
    I2C1->TXDR = (unsigned char) (address &0x00FF); /* Byte to send */
    while (!(I2C1->ISR & I2C_ISR_TXIS) ); // дожидаемся окончания отправки адреса
    I2C1->TXDR = data ; /* Byte to send */ // и отправляем байт
    timerEEPROMpause = current_millis; // обнуляем таймер ожидания следующей операции
}

void eeprom_pageclear(const unsigned short address, const unsigned char nbytes) { // очистка страницы
    delayEEPROM5msec();
    I2C1->CR2 = I2C_CR2_AUTOEND | ((2+nbytes)<<16) | (EEPROM_OWN_ADDRESS<<1); // все аналогично отправке одного байта, только количество прописываем размер страницы +2
    while (!(I2C1->ISR & I2C_ISR_TXE) ); /* Check Tx empty */
    I2C1->TXDR =(unsigned char) (address>>8); /* Byte to send */
    I2C1->CR2 |= I2C_CR2_START; /* Go */
    while (!(I2C1->ISR & I2C_ISR_TXIS) );
    I2C1->TXDR = (unsigned char)(address &0x00FF); /* Byte to send */
    for(unsigned char index=0;index<=nbytes-1;index++) { // цикл по количеству отправляемых байт
        while (!(I2C1->ISR & I2C_ISR_TXIS) ); // ждем как очистится регистр
        I2C1->TXDR = 0 ; /* Byte to send */ // пишем нули
    }
    timerEEPROMpause = current_millis;
}

void eeprom_pagewrite(const unsigned short address, const unsigned char *buf, const unsigned char nbytes) {
    delayEEPROM5msec();
    I2C1->CR2 = I2C_CR2_AUTOEND | ((2+nbytes)<<16) | (EEPROM_OWN_ADDRESS<<1); // все аналогично отправке одного байта, только количество прописываем размер страницы +2
    while (!(I2C1->ISR & I2C_ISR_TXE) ); /* Check Tx empty */
    I2C1->TXDR =(unsigned char) (address>>8); /* Byte to send */
    I2C1->CR2 |= I2C_CR2_START; /* Go */
    while (!(I2C1->ISR & I2C_ISR_TXIS) );
    I2C1->TXDR = (unsigned char)(address &0x00FF); /* Byte to send */
    for(unsigned char index=0;index<=nbytes-1;index++) { // цикл по буферу
        while (!(I2C1->ISR & I2C_ISR_TXIS) );
        I2C1->TXDR = buf[index] ; /* Byte to send */ // отправляем из буфера
    }
    timerEEPROMpause = current_millis;
}

void eeprom_pageread(const unsigned short address, unsigned char* buf, const unsigned char nbytes) {
    delayEEPROM5msec();
    I2C1->CR2 = (2<<16) | (EEPROM_OWN_ADDRESS<<1); // отправляем два байта адреса
    while (!(I2C1->ISR & I2C_ISR_TXE) );
    I2C1->TXDR = (unsigned char) (address>>8); /* Byte to send */
    I2C1->CR2 |= I2C_CR2_START; /* Go */
    while (!(I2C1->ISR & I2C_ISR_TXIS) );
    I2C1->TXDR = (unsigned char)(address &0x00FF); /* Byte to send */
    while (!(I2C1->ISR & I2C_ISR_TC) ){};
    I2C1->CR2 = I2C_CR2_AUTOEND | (nbytes<<16) | (EEPROM_OWN_ADDRESS<<1) | I2C_CR2_RD_WRN | I2C_CR2_NACK; // читаем nbytes байт
    I2C1->CR2 |= I2C_CR2_START; /* Go */
    for(unsigned char index=0;index<=nbytes-1;index++) { // цикл по буферу
        while (!(I2C1->ISR & I2C_ISR_RXNE) ){}; // ждем как появится байт
        buf[index] = I2C1->RXDR ; // читаем его в буфер
    }
}

void initEEPROMi2c(void) { // инициализация шины I2C
    // I2C1 SCL PB8
    GPIOB->MODER |= GPIO_MODER_MODER8_1; // 10 — режим альтернативной функции.
    GPIOB->MODER &= ~GPIO_MODER_MODER8_0; // 10 — режим альтернативной функции.
    GPIOB->OTYPER |= GPIO_OTYPER_OT_8; // 1 - open-drain
    GPIOB->PUPDR &= ~GPIO_PUPDR_PUPDR8_1; // 01 — подтяжка к плюсу питания или pull-up сокращено PU
    GPIOB->PUPDR |= GPIO_PUPDR_PUPDR8_0; // 01 — подтяжка к плюсу питания или pull-up сокращено PU
    GPIOB->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR8_1; // 11 — 50 MHz
    GPIOB->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR8_0; // 11 — 50 MHz
    GPIOB->AFR[1] |= (0x04); // Назначаем PB8 выводу альтернативную функцию AF4
    // I2C1 SDA PB9
    GPIOB->MODER |= GPIO_MODER_MODER9_1; // 10 — режим альтернативной функции.
    GPIOB->MODER &= ~GPIO_MODER_MODER9_0; // 10 — режим альтернативной функции.
    GPIOB->OTYPER |= GPIO_OTYPER_OT_9; // 1 - open-drain
    GPIOB->PUPDR &= ~GPIO_PUPDR_PUPDR9_1; // 01 — подтяжка к плюсу питания или pull-up сокращено PU
    GPIOB->PUPDR |= GPIO_PUPDR_PUPDR9_0; // 01 — подтяжка к плюсу питания или pull-up сокращено PU
    GPIOB->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR9_1; // 11 — 50 MHz
    GPIOB->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR9_0; // 11 — 50 MHz
    GPIOB->AFR[1] |= (0x04 << 4); // Назначаем PB9 выводу альтернативную функцию AF4
    // I2C1 init
    I2C1->CR1 = 0; // обнуляем все статусы
    RCC->APB1ENR |= RCC_APB1ENR_I2C1EN; // включаем тактирование
    RCC->CFGR3 |= RCC_CFGR3_I2C1SW;
    I2C1->TIMINGR = 0x2000090E; // таймеры - скорость шины 400 кГц
    I2C1->OAR1 = 0;
    I2C1->OAR2 = 0;
    I2C1->CR1 = I2C_CR1_PE; // включаем I2C
    timerEEPROMpause = 0UL;
}

void readEEPROMallDATA(void) { // чтение из EEPROM 24LC64 данных о MQTT серверах
#ifdef SAVE_EEPROM // если надо записать данные в EEPROM
    // save data to eeprom
    for(unsigned char i=0; i<9; ++i) eeprom_pageclear(getAddressFromNumBlock(i), EEPROM_PAGE_SIZE); // clear eeprom // очищаем EEPROM нулями
    CLEAR_EEPROM_BUF; strcpy((char *)eeprom_buf, (char *)strMqttDeviceID); eeprom_pagewrite(getAddressFromNumBlock(0),eeprom_buf , EEPROM_PAGE_SIZE); // записываем поблочно
    CLEAR_EEPROM_BUF; strcpy((char *)eeprom_buf, (char *)strMqttServer1); eeprom_pagewrite(getAddressFromNumBlock(1),eeprom_buf , EEPROM_PAGE_SIZE);
    CLEAR_EEPROM_BUF; strcpy((char *)eeprom_buf, (char *)strMqttServer2); eeprom_pagewrite(getAddressFromNumBlock(2),eeprom_buf , EEPROM_PAGE_SIZE);
    CLEAR_EEPROM_BUF; strcpy((char *)eeprom_buf, (char *)strMqttPort1); eeprom_pagewrite(getAddressFromNumBlock(3),eeprom_buf , EEPROM_PAGE_SIZE);
    CLEAR_EEPROM_BUF; strcpy((char *)eeprom_buf, (char *)strMqttPort2); eeprom_pagewrite(getAddressFromNumBlock(4),eeprom_buf , EEPROM_PAGE_SIZE);
    CLEAR_EEPROM_BUF; strcpy((char *)eeprom_buf, (char *)strMqttUser1); eeprom_pagewrite(getAddressFromNumBlock(5),eeprom_buf , EEPROM_PAGE_SIZE);
    CLEAR_EEPROM_BUF; strcpy((char *)eeprom_buf, (char *)strMqttUser2); eeprom_pagewrite(getAddressFromNumBlock(6),eeprom_buf , EEPROM_PAGE_SIZE);
    CLEAR_EEPROM_BUF; strcpy((char *)eeprom_buf, (char *)strMqttPass1); eeprom_pagewrite(getAddressFromNumBlock(7),eeprom_buf , EEPROM_PAGE_SIZE);
    CLEAR_EEPROM_BUF; strcpy((char *)eeprom_buf, (char *)strMqttPass2); eeprom_pagewrite(getAddressFromNumBlock(8),eeprom_buf , EEPROM_PAGE_SIZE);
#endif
    // read data from eeprom
    memset(mqttDeviceID,0,max_size_mqtt_device); eeprom_pageread(getAddressFromNumBlock(0),eeprom_buf , EEPROM_PAGE_SIZE); strcpy((char *)mqttDeviceID, (char *)eeprom_buf); // читаем поблочно данные в переменные
    memset(mqttServer[0],0,max_size_mqtt_device); eeprom_pageread(getAddressFromNumBlock(1),eeprom_buf , EEPROM_PAGE_SIZE); strcpy((char *)mqttServer[0], (char *)eeprom_buf);
    memset(mqttServer[1],0,max_size_mqtt_device); eeprom_pageread(getAddressFromNumBlock(2),eeprom_buf , EEPROM_PAGE_SIZE); strcpy((char *)mqttServer[1], (char *)eeprom_buf);
    memset(mqttPort[0],0,max_size_mqtt_port); eeprom_pageread(getAddressFromNumBlock(3),eeprom_buf , EEPROM_PAGE_SIZE); strcpy((char *)mqttPort[0], (char *)eeprom_buf);
    memset(mqttPort[1],0,max_size_mqtt_port); eeprom_pageread(getAddressFromNumBlock(4),eeprom_buf , EEPROM_PAGE_SIZE); strcpy((char *)mqttPort[1], (char *)eeprom_buf);
    memset(mqttUser[0],0,max_size_mqtt_device); eeprom_pageread(getAddressFromNumBlock(5),eeprom_buf , EEPROM_PAGE_SIZE); strcpy((char *)mqttUser[0], (char *)eeprom_buf);
    memset(mqttUser[1],0,max_size_mqtt_device); eeprom_pageread(getAddressFromNumBlock(6),eeprom_buf , EEPROM_PAGE_SIZE); strcpy((char *)mqttUser[1], (char *)eeprom_buf);
    memset(mqttPass[0],0,max_size_mqtt_device); eeprom_pageread(getAddressFromNumBlock(7),eeprom_buf , EEPROM_PAGE_SIZE); strcpy((char *)mqttPass[0], (char *)eeprom_buf);
    memset(mqttPass[1],0,max_size_mqtt_device); eeprom_pageread(getAddressFromNumBlock(8),eeprom_buf , EEPROM_PAGE_SIZE); strcpy((char *)mqttPass[1], (char *)eeprom_buf);
}


А разницы нет что у тебя используется F30x, что у меня F103 ?

разница конечно же есть, но надо просто сравнить DS / имена регистров / подправить, в среднем все очень похоже.

Много раз уже переносил наработки с F303 на F103 или F411.

попался неплохой сайт про стм-ы

Коллеги, никто не видел отладчик/просмотрщик STM32 Serial Wire Viewer чтоб русский UTF-8 мог отображать?

А если через putty?

а он умеет? никогда бы не подумал, это же не COM Порт.