161 Востаннє редагувалося fronders (20.06.2019 17:20:06)

Re: STM32, Atolic TrueStudio, CubeMX

taburyak вітаю ;)

по-перше найцікавіша частина ініціалізації таймера залишилась поза зором - функцію HAL_TIM_IC_MspInit() в студію :)
а переривань не відбувається, бо мабуть в налаштуваннях NVIC не включене (розмасковане) перерирвання TIM2 Global Interrupt.

UPD: або проблема в тому що тригер налаштований на falling

sSlaveConfig.TriggerPolarity = TIM_INPUTCHANNELPOLARITY_FALLING;

і по ньому з одного боку скидається таймер, а по-друге виконується захват сигналу (який в цей момент нуль). Результат захвату треба забирати не з регістру CNT а регістру каналу, відповідно CCR1.

по-друге можу підказати як міряти простіше: можна налаштувати два канали на одну ніжку (наприклад channel 1 в режимі direct mode з трігером по rising, channel 2 - indirect mode з трігером по falling). тоді обробник переривання буде наступного вигляду:

HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_1);
HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_2);
uint32_t pulse;

void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim) {
    static uint32_t rising;
    if (htim->Instance == TIM2) {
        if (htim->Channel == HAL_TIM_ACTIVE_CHANNEL_1) {
            rising = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1);
        } else if (htim->Channel == HAL_TIM_ACTIVE_CHANNEL_2) {
            pulse = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_2) - rising;
        }
    }
}

трігер тоді взагалі не потрібен, а якщо зробити період таймеру максимальним (2^32-1) то тоді і переповнення буде автоматично працювати через unsigned математику.

або залишити так само два канали direct + indirect з різнимим тригерами. і по TI1 ресетити таймер як у вас, а по TI2 робити семпл:

HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_2);
uint32_t pulse;

void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim) {
    if (htim->Instance == TIM2) {
        } else if (htim->Channel == HAL_TIM_ACTIVE_CHANNEL_2) {
            pulse = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_2);
        }
    }
}
Подякували: taburyak1

162

Re: STM32, Atolic TrueStudio, CubeMX

https://replace.org.ua/misc.php?action=pun_attachment&item=1992&download=0
Увімкнено.
Rising теж не допоміг.
Спробував по вашому, теж не потрапляє до коллбєку по перериванням.
Я напевно щось взагалі не розумію. По ідеї проста річ. А я без поняття.

Post's attachments

interput_tim2.png 28.19 kb, 93 downloads since 2019-06-20 

163 Востаннє редагувалося fronders (20.06.2019 17:30:16)

Re: STM32, Atolic TrueStudio, CubeMX

знайшов в чому проблема. створив новий проект за своєю задумкою, але вставив шмат вашого коду колбека. переривання спрацьовує, а колбек не викликається. подивився уважніше, а там в імені функції помилка (велика літера у CallBack, а треба Callback)

HAL_TIM_IC_CaptureCallback()

А не ругається бо є weak реалізація в надрах HAL ;)

p.s. все одно в мене вже все запрацювало - поділюсь одразу всім проектом (там як я і спершу описував direct rising + indirect falling, без reset)  https://www.dropbox.com/s/r30zrfdrq5jae … h.zip?dl=0

Подякували: taburyak, ReAl2

164

Re: STM32, Atolic TrueStudio, CubeMX

fronders написав:

p.s. все одно в мене вже все запрацювало - поділюсь одразу всім проектом (там як я і спершу описував direct rising + indirect falling, без reset)  https://www.dropbox.com/s/r30zrfdrq5jae … h.zip?dl=0

Дякую, завтра спробую.

165

Re: STM32, Atolic TrueStudio, CubeMX

fronders написав:

знайшов в чому проблема. створив новий проект за своєю задумкою, але вставив шмат вашого коду колбека. переривання спрацьовує, а колбек не викликається. подивився уважніше, а там в імені функції помилка (велика літера у CallBack, а треба Callback)

Так, щиро дякую, помилка в неправильній назві колбєка. Але ланка на проект щось не показує сам проект. Бо хоч в колбєк я попадаю, але щось ніфіга воно не рахує довжину імпульсу.

166

Re: STM32, Atolic TrueStudio, CubeMX

fronders написав:

p.s. все одно в мене вже все запрацювало - поділюсь одразу всім проектом (там як я і спершу описував direct rising + indirect falling, без reset)

Щиро дякую ще раз. Наче щось рахує :)

А от якщо потрібно рахувати оберти валу двигуна, та оберти валу вже після редуктора, то це потрібно на окремому таймері організовувати по аналогії?

167

Re: STM32, Atolic TrueStudio, CubeMX

Ще питання по таймерам. МК зараз тактується 72МГц
В коді ініціалізації таймеру, в мене prescaler задається так:

htim2.Init.Prescaler = 72-1;

Це жорстка прив'язка до тактової частоти мікроконтролера.
Щоб було більш гнучко, я спробував після ініціалізації таймеру додати такий рядок:

__HAL_TIM_SET_PRESCALER(&htim2, (HAL_RCC_GetSysClockFreq() / 1000000) - 1);


Де prescaler визначається як частота мікроконтролера в мегагерцах і віднімаємо одиницю. Щоб, якщо буде мінятись в проекті частота мікроконтролера, то й автоматично "підлаштовувався" prescaler таймеру.
Це вірне/нормальне рішення? Після макроса __HAL_TIM_SET_PRESCALER потрібно якось застосувати зміни? Чи достатньо цього рядку - __HAL_TIM_SET_PRESCALER ?

168

Re: STM32, Atolic TrueStudio, CubeMX

taburyak написав:

А от якщо потрібно рахувати оберти валу двигуна, та оберти валу вже після редуктора, то це потрібно на окремому таймері організовувати по аналогії?

На окремому каналі capture того ж таймера, у перериванні розбирати від якого каналу воно.

Подякували: taburyak1

169

Re: STM32, Atolic TrueStudio, CubeMX

taburyak написав:

Щоб було більш гнучко, я спробував після ініціалізації таймеру додати такий рядок:

__HAL_TIM_SET_PRESCALER(&htim2, (HAL_RCC_GetSysClockFreq() / 1000000) - 1);


Де prescaler визначається як частота мікроконтролера в мегагерцах і віднімаємо одиницю. Щоб, якщо буде мінятись в проекті частота мікроконтролера, то й автоматично "підлаштовувався" prescaler таймеру.
Це вірне/нормальне рішення? Після макроса __HAL_TIM_SET_PRESCALER потрібно якось застосувати зміни? Чи достатньо цього рядку - __HAL_TIM_SET_PRESCALER ?

А там є ще якісь запити, окрім HAL_RCC_GetSysClockFreq()?
Таймери ж різні сидять на APB1/APB2, у кожної свій прескалер. Якщо робити зовсім чесно, то треба враховувати, що TIMxCLK може бути не рівною SYSCLK.

А так наче все нормально.

Подякували: taburyak1

170

Re: STM32, Atolic TrueStudio, CubeMX

ReAl написав:

На окремому каналі capture того ж таймера, у перериванні розбирати від якого каналу воно.

Так, вже зробив. Рахує і там і там. Чудово так.

171

Re: STM32, Atolic TrueStudio, CubeMX

ReAl написав:

А там є ще якісь запити, окрім HAL_RCC_GetSysClockFreq()?
Таймери ж різні сидять на APB1/APB2, у кожної свій прескалер. Якщо робити зовсім чесно, то треба враховувати, що TIMxCLK може бути не рівною SYSCLK.
А так наче все нормально.

Так, я зовсім про це не подумав. Звісно є і інші запити. Вже пізніше гляну. Щиро дякую.

172

Re: STM32, Atolic TrueStudio, CubeMX

Всім вітаннячко!
Штурмую дисплей ILI9341 по 8080 (FSMC). Вже до купи склав бібліотечку (ще сирувата, пилю терпухом). Але захотілось ще додати до бібліотеки функцію читання пікселя. Щоб коли, наприклад за допомоги тачскріну намалював щось, то потім була можливість зберегти зображення на флешку. Так ось, регістри читаю нормально, значення адекватні, правильні. Т.е. функція читання нормально працює. Але якщо я записую піксель з кольором, наприклад,  0xAFE5. То читаю я вже той самий піксель вже з кольором 0xACFC.

Ось мої дефайни на читання, писання:

#define LCD_BASE0                ((uint32_t)0x60000000)
#define LCD_BASE1                ((uint32_t)0x60080000)

#define LCD_CmdWrite(command)    *(volatile uint16_t *) (LCD_BASE0) = (command)
#define LCD_DataWrite(data)        *(volatile uint16_t *) (LCD_BASE1) = (data)
#define    LCD_StatusRead()        *(volatile uint16_t *) (LCD_BASE0) //if use read  Mcu interface DB0~DB15 needs increase pull high
#define    LCD_DataRead()            *(volatile uint16_t *) (LCD_BASE1) //if use read  Mcu interface DB0~DB15 needs increase pull high

Ось малюємо піксель:

void lcdDrawPixel(uint16_t x, uint16_t y, uint16_t color)
{
  lcdSetWindow(x, x, y, y);
  lcdWriteData(color);
}

Де:

void lcdSetWindow(unsigned short x0, unsigned short y0, unsigned short x1, unsigned short y1)
{
  lcdWriteCommand(ILI9341_COLADDRSET);
  lcdWriteData((x0 >> 8) & 0xFF);
  lcdWriteData(x0 & 0xFF);
  lcdWriteData((y0 >> 8) & 0xFF);
  lcdWriteData(y0 & 0xFF);
  lcdWriteCommand(ILI9341_PAGEADDRSET);
  lcdWriteData((x1 >> 8) & 0xFF);
  lcdWriteData(x1 & 0xFF);
  lcdWriteData((y1 >> 8) & 0xFF);
  lcdWriteData(y1 & 0xFF);
  lcdWriteCommand(ILI9341_MEMORYWRITE);
}

А ось читання пікселя:

uint16_t lcdReadPixel(uint16_t x, uint16_t y)
{
    lcdSetWindow(x, x, y, y);
    lcdWriteCommand(ILI9341_MEMORYREAD);
    lcdReadData();
    return lcdReadData();
}

Ну і що йому не так? Координати (адреса) пікселя співпадають. По логіці що поклав в певну адресу пам'яті, то і те саме має ж прочитатись. Дисплей кольори відображає без спотворень, так як треба. Що не так? В чому хитрість?

173 Востаннє редагувалося fronders (28.09.2019 11:18:47)

Re: STM32, Atolic TrueStudio, CubeMX

@taburyak я таки розібрався! :)

Справа в тому що екран повертає дані в форматі 888. Тобто для зчитування одного пікселю треба зробити два рази Read по 16 біт в результаті отримаємо два шматка: [R1G1][B1R2]. З яких забираємо три байти кольору, і потім ще треба привести до формату 565 (у мене для цього є окрема функція)

Ввідні дані: весь екран залитий кольором 0x1234, один піксель залив 0x4321.
Ось тут зробив послідовно десять разів LCD_RD_Data() в масив temp. (нульова ячейка - dummy read)
https://i.ibb.co/X2Snph4/Capture.png
як бачиш паттерн повторюється 10 44 a4 (це у 888 що відповідає 0x1234 у форматі 565) - фоновий колір. А наш пацієнт це 40 64 08 (це у 888 форматі відповідає 0x4321 у форматі 565) - колір замальованого пікселя.

Функція що робить перетворення 888 -> 565:

/**
 * \brief Calculate 16Bit-RGB
 *
 * \param r    Red
 * \param g    Green
 * \param b    Blue
 *
 * \return uint16_t    16Bit-RGB
 */
uint16_t LCD_Color565(uint8_t r, uint8_t g, uint8_t b) {
    return ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | (b >> 3);
}

Плюс не потрібно виставляти ціле вікно для отримання пікселю, достатньо виставити лише лівий верхній кут. Ось так виглядає функція ReadPixel:

/**
 * \brief Reads a point from the specified coordinates
 *
 * \param x        x-Coordinate
 * \param y        y-Coordinate
 *
 * \return uint16_t     Color
 */
uint16_t LCD_ReadPixel(int16_t x, int16_t y) {
    uint16_t temp[3];
    // Clip
    if ((x < 0) || (y < 0) || (x >= TFTWIDTH) || (y >= TFTHEIGHT))
        return;
    LCD_WR_REG(ILI9341_COLADDRSET);
    LCD_WR_Data(x >> 8);
    LCD_WR_Data(x & 0xFF);

    LCD_WR_REG(ILI9341_PAGEADDRSET);
    LCD_WR_Data(y >> 8);
    LCD_WR_Data(y & 0xFF);

    LCD_WR_REG(ILI9341_MEMORYREAD);
    temp[0] = LCD_RD_Data(); // dummy read
    temp[1] = LCD_RD_Data();
    temp[2] = LCD_RD_Data();
    
    return LCD_Color565((temp[1] >> 8) & 0xFF, temp[1] & 0xFF, (temp[2] >> 8) & 0xFF);
}

Ось так у мене виглядає DrawPixel - ставлю тільки x,y (без другої точки кінця вікна):

/**
 * \brief Draws a point at the specified coordinates
 *
 * \param x        x-Coordinate
 * \param y        y-Coordinate
 * \param color    Color
 *
 * \return void
 */
void LCD_DrawPixel(int16_t x, int16_t y, uint16_t color) {
    // Clip
    if ((x < 0) || (y < 0) || (x >= TFTWIDTH) || (y >= TFTHEIGHT))
        return;
    LCD_WR_REG(ILI9341_COLADDRSET);
    LCD_WR_Data(x >> 8);
    LCD_WR_Data(x & 0xFF);

    LCD_WR_REG(ILI9341_PAGEADDRSET);
    LCD_WR_Data(y >> 8);
    LCD_WR_Data(y & 0xFF);

    LCD_WR_REG(ILI9341_MEMORYWRITE);
    LCD_WR_Data(color);
}

І пам'ятаєш казав у тебе правильно працює але невірно зроблена функція SetWindow - переплутані місцями x1, x2, y1, y2 і в аргументах і всередині. Потрібно передавати

LCD_SetAddrWindow (x1, y1, x2, y2)

І тоді в CASET писати х1/х2, а в PASET - y1/y2. А у тебе навпаки :)

Сама функція:

/**
 * \brief Sets window address
 *
 * \param x1         Left top window x-coordinate
 * \param y1         Left top window y-coordinate
 * \param x2         Rigth bottom window x-coordinate
 * \param y2         Rigth bottom window y-coordinate
 *
 * \return void
 */
void LCD_SetAddrWindow(int x1, int y1, int x2, int y2) {
    LCD_WR_REG(ILI9341_COLADDRSET);
    LCD_WR_Data(x1 >> 8);
    LCD_WR_Data(x1 & 0xFF);
    LCD_WR_Data(x2 >> 8);
    LCD_WR_Data(x2 & 0xFF);
    LCD_WR_REG(ILI9341_PAGEADDRSET);
    LCD_WR_Data(y1 >> 8);
    LCD_WR_Data(y1 & 0xFF);
    LCD_WR_Data(y2 >> 8);
    LCD_WR_Data(y2 & 0xFF);
    LCD_WR_REG(ILI9341_MEMORYWRITE);
}
Подякували: taburyak, leofun01, ReAl3

174

Re: STM32, Atolic TrueStudio, CubeMX

@fronders щира подяка. Все з подробицями розписав. Все зрозуміло мені. Все виправив. Працює як слід. Поки виправляв, знайшов ще деякі місця для покращення швидкості. Тепер в мене замальоване коло (fillCircle) малюється майже в 10 разів швидше чим було. А також в мене дуже повільна функція drawChar. Я навіть знаю з-за чого, але по іншому я не можу второпати як переписати функцію. Вже по різному мудрував, але ні як. Як буде ласка, підкажи як по іншому зробити функцію. Бо зараз кожен піксель шрифту малюється окремо функцією drawPixel і це дуже повільно. А треба встановити вікно і просто кинути з шрифтів дамп даних для конкретного char'у і щоб враховувався розмір шрифта і все таке.

Ось моє повільне позорище, навіть соромно викладувати:

void lcdDrawChar(int16_t x, int16_t y, unsigned char c, uint16_t color, uint16_t bg)
{
    if ((x >= lcdProperties.width) ||             // Clip right
            (y >= lcdProperties.height) ||         // Clip bottom
            ((x + lcdFont.pFont->Width) < 0) || // Clip left
            ((y + lcdFont.pFont->Height) < 0))  // Clip top
        return;

    uint8_t fontCoeff = lcdFont.pFont->Height / 8;
    uint8_t xP = 0;

    for(uint8_t i = 0; i < lcdFont.pFont->Height; i++)
    {
        uint8_t line;

        for(uint8_t k = 0; k < fontCoeff; k++)
        {
            line = lcdFont.pFont->table[((c - 0x20) * lcdFont.pFont->Height * fontCoeff) + (i * fontCoeff) + k];

            for(uint8_t j = 0; j < 8; j++)
            {
                if((line & 0x80) == 0x80)
                {
                    lcdDrawPixel(x + j + xP, y + i, color);
                }
                else if (bg != color)
                {
                    lcdDrawPixel(x + j + xP, y + i, bg);
                }
                line <<= 1;
            }

            xP += 8;
        }

        xP = 0;
    }
}

175

Re: STM32, Atolic TrueStudio, CubeMX

Треба б мені прикупити різних плат, щоб на одній хвилі бути :-)

Подякували: taburyak1

176

Re: STM32, Atolic TrueStudio, CubeMX

ReAl написав:

Треба б мені прикупити різних плат, щоб на одній хвилі бути :-)

Таки так. Порадити щось можу?

177

Re: STM32, Atolic TrueStudio, CubeMX

taburyak написав:
ReAl написав:

Треба б мені прикупити різних плат, щоб на одній хвилі бути :-)

Таки так. Порадити щось можу?

Списочок лінків на плати і де беруть ще хоча б годинку на добу :)
Або хоча б перше, друге мо десь у хаті завалялося, пошукаю ;)

178

Re: STM32, Atolic TrueStudio, CubeMX

ReAl написав:

Списочок лінків на плати і де беруть ще хоча б годинку на добу :)
Або хоча б перше, друге мо десь у хаті завалялося, пошукаю ;)

Зрозумів про список лінків. Далі я не зрозумів. "Беруть годину на добу"  - що саме і де? :)

Подякували: ReAl1

179

Re: STM32, Atolic TrueStudio, CubeMX

Мучився я мучився самотужки, так і не вийшло в мене  придумати сторінкове багаторівневе меню, щоб зручно було додавати/прибирати пункти меню і сторінки. Щоб зручно було назначати функції на виконання. В процесі розробки коду.
Постало питання використати чужі праці в цьому питанні. В репозиторії Arduino IDE є більше десятка бібліотек про "меню". Розбиратись з усіма - життя не вистачить.
Може хто вже на тих "меню" собаку з'їв? І може щось мені порадити?
Що мені потрібно:

  • Структура, чи ще якісь способи структурізації, де буде зберігатись індекс сторінки меню, батьківська сторінка, дитяча сторінка і якийсь масив, чи ще якось структуризувати і зберігати, де буде перелік пунктів меню, які входять до певної сторінки меню.

  • Структура, чи ще якійсь спосіб структурізації, де буде зберігатись індекс пункту меню, його назва, значення, та поінтер на функцію, яка буде виконуватись при натисканні на цей пункт меню.

Ну звісно ці структури я в змозі оформити як слід. Але далі я не можу зрозуміти як то всім тим керувати. Якісь потрібні функції зворотнього зв'язку? Вопшем далі оголошення структур в мене ступор.

typedef const struct ItemMenu
{    
    const int index;    
    void(*EnterCallback) (void);
    const char Text[16];
    const char Value[16];
}ItemMenuStruct;

typedef const struct PageMenu
{
    const struct PageMenu *Parent;
    const struct PageMenu *Child;
    const struct ItemMenu *ItemList;
}ItemMenuStruct;

180

Re: STM32, Atolic TrueStudio, CubeMX

taburyak написав:
ReAl написав:

Списочок лінків на плати і де беруть ще хоча б годинку на добу :)
Або хоча б перше, друге мо десь у хаті завалялося, пошукаю ;)

Зрозумів про список лінків. Далі я не зрозумів. "Беруть годину на добу"  - що саме і де? :)

Так от і мені цікаво — де :D
Так, щоб я прийшов додому після роботи, повечеряв, те-се, а тоді з 23:00 до 24:59 ще дві годинки поколупався у цікавим.

Подякували: taburyak1