Кто любит RISC в жизни, заходим, не стесняемся.
Ответить

Re: STM32 новичку в ARM что к чему

Пт янв 13, 2023 07:51:25

деление на 10 через сдвиги

Деление на константу легко преобразуется в умножение. Сдвиг там используется однократно или вообще не используется, если речь идет о степени двойки 8, 16 или 32.
Например:
Y=X/10=X*6554/65536=X/9.99939
или
Y=X/10=X*429496730/4294967296=X/9.99999999

Re: STM32 новичку в ARM что к чему

Пт янв 13, 2023 09:48:20

Да, почти первый вариант: для uint8 или uint16, чтобы не выходить за пределы uint32, т.к. арифметика uint64 тоже связана с накладными расходами (хотя, все равно быстрей, чем совтовое деление).

Re: STM32 новичку в ARM что к чему

Сб янв 14, 2023 16:48:52

В общем, с RTC завел вот такую структуру:
Код:
typedef struct{
    uint8_t second;
    uint8_t minute;
    uint8_t hour;
    uint8_t weekday;
    uint8_t day;
    uint8_t month;
    uint8_t year;
} rtc_t;

Дальше - под спойлером, чтобы не загромождать.
СпойлерДля сеттеров вот так:
Код:
static uint8_t div10b(uint8_t i, uint8_t *r){ // divide by 10
    uint32_t u = i;
    u *= 52429;
    u >>= 19;
    if(r) *r = i - 10*u;
    return (uint8_t)u;
}

static uint8_t DEC2BCD(uint8_t x){
    uint8_t d, r;
    d = div10b(x, &r);
    return (d << 4 | r);
}

int rtc_setdate(rtc_t *d){
    if(d->year > 99) return FALSE;
    if(d->month > 12 || d->month == 0) return FALSE;
    if(d->day > maxdays[d->month - 1] || d->day == 0) return FALSE;
    if(d->month == 2 && d->day == 29){
        uint8_t test = (d->year >> 2) << 2;
        if(d->year != test) return FALSE; // not leap year
    }
    if(d->weekday > 7 || d->weekday == 0) return FALSE;
    RTC->ICSR |= RTC_ICSR_INIT;
    WAITWHILE(!(RTC->ICSR & RTC_ICSR_INITF));
    RTC->DR = DEC2BCD(d->year) << RTC_DR_YU_Pos | d->weekday << RTC_DR_WDU_Pos | DEC2BCD(d->month) << RTC_DR_MU_Pos | DEC2BCD(d->day) << RTC_DR_DU_Pos;
    RTC->ICSR &= ~RTC_ICSR_INIT;
    return TRUE;
}

int rtc_settime(rtc_t *t){
    if(t->hour > 23) return FALSE;
    if(t->minute > 59) return FALSE;
    if(t->second > 59) return FALSE;
    RTC->ICSR |= RTC_ICSR_INIT;
    WAITWHILE(!(RTC->ICSR & RTC_ICSR_INITF));
    RTC->TR = DEC2BCD(t->hour) << RTC_TR_HU_Pos | DEC2BCD(t->minute) << RTC_TR_MNU_Pos | DEC2BCD(t->second) << RTC_TR_SU_Pos;
    RTC->ICSR &= ~RTC_ICSR_INIT;
    return TRUE;
}

Геттер на все:
Код:
void get_curtime(rtc_t *t){
    WAITWHILE(!(RTC->ICSR & RTC_ICSR_RSF));
    register uint32_t r = RTC->TR;
    #define BCDu(shift)     ((r >> shift) & 0xf)
    t->second = BCDu(RTC_TR_SU_Pos) + 10 * BCDu(RTC_TR_ST_Pos);
    t->minute = BCDu(RTC_TR_MNU_Pos) + 10 * BCDu(RTC_TR_MNT_Pos);
    t->hour = BCDu(RTC_TR_HU_Pos) + 10 * BCDu(RTC_TR_HT_Pos);
    r = RTC->DR;
    t->day = BCDu(RTC_DR_DU_Pos) + 10 * BCDu(RTC_DR_DT_Pos);
    t->month = BCDu(RTC_DR_MU_Pos);
    if(r & RTC_DR_MT) t->month += 10;
    t->weekday = (r >> RTC_DR_WDU_Pos) & 0x7;
    t->year = BCDu(RTC_DR_YU_Pos) + 10 * BCDu(RTC_DR_YT_Pos);
}

И сеттер/геттер калибровки:
Код:
int rtc_setcalib(int calval){
    if(calval < -511 || calval > 512) return FALSE;
    uint32_t calp = 0, calm = 0;
    if(calval < 0)  calm = -calval;
    else if(calval > 0){
        calp = RTC_CALR_CALP;
        calm = 512 - calval;
    }
    // unlock RCC
    RTC->WPR = 0xCA;
    RTC->WPR = 0x53;
    RTC->CALR = calp | calm;
    return 1;
}

int rtc_getcalib(){
    int calval = (RTC->CALR & RTC_CALR_CALP) ? 512 : 0;
    calval -= RTC->CALR & 0x1ff;
    return calval;
}

А уж из полученного времени легко построить в формате утилиты date:
Код:
static const char *weekdays[] = {"Mon", "Tue", "Wed", "Thur", "Fri", "Sat", "Sun"};
static const char *months[] = {"Jan", "Feb", "Mar", "Apr", "May", "June", "July", "Aug", "Sept", "Oct", "Nov", "Dec"};

static void prezero(uint8_t x){
    if(x < 10){ putch(&#39;0&#39;); putch(&#39;0&#39; + x);}
    else USND(u2str(x));
}

void print_curtime(){
    rtc_t t;
    get_curtime(&t);
    USND(weekdays[t.weekday - 1]);
    putch(&#39; &#39;);
    USND(months[t.month - 1]);
    putch(&#39; &#39;);
    USND(u2str(t.day));
    putch(&#39; &#39;);
    prezero(t.hour);
    putch(&#39;:&#39;);
    prezero(t.minute);
    putch(&#39;:&#39;);
    prezero(t.second);
    USND(" 20"); prezero(t.year);
    putch(&#39;\n&#39;);
}

Еще у меня там есть сеттеры даты/времени из введенного пользователем, но это уж на гитхабе у меня смотрите.


Добавлено after 4 minutes 9 seconds:
А, блин, проверку деления на 4 неправильно сделал. Только сейчас заметил!
исправил
Последний раз редактировалось Eddy_Em Сб янв 14, 2023 16:58:34, всего редактировалось 1 раз.

Re: STM32 новичку в ARM что к чему

Сб янв 14, 2023 16:54:25

какая неэкономичная структура

Re: STM32 новичку в ARM что к чему

Сб янв 14, 2023 16:59:09

Martian, с чего бы неэкономичная? Все, что нужно. При желании можно даже упаковать (но мне это не нужно: памяти в G0, как грязи).

Re: STM32 новичку в ARM что к чему

Сб янв 14, 2023 17:46:14

Eddy_Em, на Cortex-M0 можно через div, на Cortex-M4 компилятор сам умеет.
Изображение
изображение_2023-01-14_174541286.png
(63.37 KiB) Скачиваний: 278

Re: STM32 новичку в ARM что к чему

Сб янв 14, 2023 17:54:58

VladislavS, библиотечная div через умножение и сдвиги что ли работает? В любом случае, чаще всего нужно лишь деление на 10, а оно легко реализуется.

Re: STM32 новичку в ARM что к чему

Сб янв 14, 2023 17:58:05

да не бред ли это?! что же там у вас за такие критичные ко времени задачи, что микросекунда расчетов так напрягает?!

Re: STM32 новичку в ARM что к чему

Сб янв 14, 2023 18:03:09

Бред - флоаты пихать в 8-битную аврку. А деление оптимизировать — вполне нормально, даже если эта функция и вызывается нечасто. Ведь Cortex-M0 не умеет деление. А уж если нужно часто что-то делить на константу, так тем паче оптимизация хорошо сэкономит такты.
Это ардуинщикам наплевать, что там "под капотом" происходит. Они спокойно могут аж на пару миллисекунд вызвать какую-нибудь блокирующую операцию и не париться… А то и вообще блокирующими вызовами в течение аж сотни миллисекунд ногодрыгом перегонять изображение из буфера памяти на экранчик (хотя даже если нет DMA, это на прерываниях таймера можно сделать — будет между посылками хоть время на что-нибудь полезное).

Re: STM32 новичку в ARM что к чему

Сб янв 14, 2023 18:05:09

чаще всего нужно лишь деление на 10

КОМУ нужно чаще всего? Я вот прикинул для своих проектов и не нашел деления на 10 вообще. Правда нашел множество делений на переменную, но посчитать сколько там делений на 10, а сколько на другую величину не представляется возможным...

Re: STM32 новичку в ARM что к чему

Сб янв 14, 2023 18:23:32

да не бред ли это?!
Бред это блинк на 5 кБ. А когда пишешь библиотечный код, чем Eddy_Em и занимается, надо писать оптимально даже ценой усложнения.

Re: STM32 новичку в ARM что к чему

Сб янв 14, 2023 18:40:21

VladislavS, имеет ли право на жизнь такой вариант, поморгать светодиодом?
СпойлерЧип f100
Код:
  RCC->APB2ENR |= RCC_APB2ENR_IOPCEN;
 
  GPIOC->CRH |= GPIO_CRH_CNF8_1 | GPIO_CRH_CNF9_1;
  GPIOC->CRH &= ~(GPIO_CRH_CNF8_0 | GPIO_CRH_CNF9_0);
  GPIOC->CRH &= ~(GPIO_CRH_MODE8_1 | GPIO_CRH_MODE9_1);
  GPIOC->CRH |= GPIO_CRH_MODE8_0 | GPIO_CRH_MODE9_0;
 
  RCC->APB2ENR |= RCC_APB2ENR_AFIOEN;
  AFIO->MAPR |= AFIO_MAPR_TIM3_REMAP;
 
  RCC->APB1ENR |= RCC_APB1ENR_TIM3EN;
 
  TIM3->CR1 = 0;
  TIM3->PSC = 0;
  TIM3->ARR = 0;
  TIM3->CCR3 = 0;
  TIM3->CCR4 = 0;
  TIM3->CCMR2 = TIM_CCMR2_OC3M_2 | TIM_CCMR2_OC3M_1; 
  TIM3->CCMR2 |= TIM_CCMR2_OC4M_2 | TIM_CCMR2_OC4M_1;
  TIM3->CCER = TIM_CCER_CC3E | TIM_CCER_CC4E;
  TIM3->CR1 |= TIM_CR1_CEN;
Код:
   TIM3->CCR3 ^= 1;   // 7 тактов   
   TIM3->CCR3 = 1;      // 2 такта   
   TIM3->CCR3 = 0;      // 2 такта
и соответственно TIM3->CCR4
У кого хороший осциллограф, проверьте будет ли там что либо, типа иголок или еще что?

Re: STM32 новичку в ARM что к чему

Сб янв 14, 2023 19:05:04

Нормальная практика - генерация импульсов при помощи таймера и ШИМ-выхода. При 0 в регистре сравнения иголок на выходе не возникает, потому что переключение сигналов происходит в момент смены счетчика, синхронно по тактовому сигналу.
Чаще всего конечно этот вариант используется не для мигания отдельного светика, а для ШИМ-генерации или генерации меандра для "пищалки". Но можно организовать и ШИМ-мигание светика, подобное лампе накаливания, то есть с плавным зажиганием/выключением.
Последний раз редактировалось MLX90640 Сб янв 14, 2023 19:07:04, всего редактировалось 1 раз.

Re: STM32 новичку в ARM что к чему

Сб янв 14, 2023 19:06:29

Мигает? Значит имеет. Хоть и отвратительно написано.

Re: STM32 новичку в ARM что к чему

Сб янв 14, 2023 19:13:49

MLX90640 писал(а):При 0 в регистре сравнения иголок на выходе не возникает
Меня интересует что будет при единице?
К сожалению у меня нету хорошего осциллографа, только аналоговый С1-72.
Только разве что ножку завести на внешнее прерывание, и в отладчике глянуть, если прерывание сработает - значит иголки присутствуют.
VladislavS писал(а):Хоть и отвратительно написано.
А как надо?

Re: STM32 новичку в ARM что к чему

Сб янв 14, 2023 19:47:20

да не бред ли это?!
Бред это блинк на 5 кБ. А когда пишешь библиотечный код, чем Eddy_Em и занимается, надо писать оптимально даже ценой усложнения.

имхо, нормальная библиотека должна быть, во-первых, читаемой (без битовой магии и т.п. замен деления умножением), а во-вторых, не должна превращаться в тыкву при переходе на другой МК, иначе это не библиотека, а костыль индивидуального изготовления - уникальный, но никому, кроме одного инвалида, не подходящий.

а блинк на 5к за 5 минут, имхо, лучше, чем блинк в 0.5к за 20 лет...

Re: STM32 новичку в ARM что к чему

Сб янв 14, 2023 19:51:47

ARV писал(а):а блинк на 5к за 5 минут, имхо, лучше, чем блинк в 0.5к за 20 лет...
Это хорошо когда флеша 128 К, а вот когда всего 16 К, стоит задуматься.

Re: STM32 новичку в ARM что к чему

Сб янв 14, 2023 19:56:26

читаемой (без битовой магии и т.п. замен деления умножением)...

Библиотека может содержать все что угодно. Ее задача скрыть некие относительно часто используемые сущности в функции. И все.
Переносимость библиотеки - это какое то недоразумение. Невозможно перенести библиотеку на совершенно другую вычислительную архитектуру без каких либо правок. Либо эта библиотека будет иметь безобразную реализацию для примитивных и не требовательных к ресурсам задач.
Не для того пользователь какого нибудь Blackfin платит 25 долларов за чип, чтобы не использовать особенности архитектуры, которые позволяют решить поставленную задачу именно на этом чипе, а не требуют другой - за 200 баксов.

Re: STM32 новичку в ARM что к чему

Сб янв 14, 2023 20:03:01

имхо, нормальная библиотека должна быть, во-первых, читаемой
Читаемым и документированным должен быть интерфейс библиотеки. Что у неё внутри исключительно головняк автора.

(без битовой магии и т.п. замен деления умножением),
Ну и где же нам деление на Cortex-M0 взять?

а во-вторых, не должна превращаться в тыкву при переходе на другой МК,
Согласен, если модуль есть на разных МК, то в идеале должен на них одинаково хорошо работать.

иначе это не библиотека, а костыль индивидуального изготовления - уникальный, но никому, кроме одного инвалида, не подходящий.
Библиотека под конкретный микроконтроллер тоже имеет право на существование. Лучше, конечно, писать универсально, но это и не всегда возможно, и зачастую тяжёлую артиллерию требует.

а блинк на 5к за 5 минут, имхо, лучше, чем блинк в 0.5к за 20 лет...
А ещё лучше блинк 0.4к за 4 минуты.

Re: STM32 новичку в ARM что к чему

Сб янв 14, 2023 20:07:40

Меня интересует что будет при единице?

Поправочка. Вы имеете ввиду при ARR = 1 и при CRRx = 1? Меандр получится, 50% ШИМ
Последний раз редактировалось MLX90640 Сб янв 14, 2023 20:24:30, всего редактировалось 1 раз.
Ответить