fa
Feedback
Doque Embedded

Doque Embedded

رفتن به کانال در Telegram

С/С++, memes and random things

نمایش بیشتر
3 569
مشترکین
اطلاعاتی وجود ندارد24 ساعت
+137 روز
+3430 روز
آرشیو پست ها
Worst synth ever. Но хотя бы уже пищит.

Про кризис. Ссаные TL072 не купить. [not flipper-related]
Про кризис. Ссаные TL072 не купить. [not flipper-related]

Пока Флипперы производятся, мы решили дать возможность живым разработчикам познакомиться с нашим кодом и железом, а также потусоваться в приятной компании чисто по-кайфу. https://habr.com/ru/company/flipperdevices/blog/589585/

Божественный прототип и бездушное заводское поделие.
+1
Божественный прототип и бездушное заводское поделие.

Ну и вот уже реальное устройство.
Ну и вот уже реальное устройство.

Оч клевый ручной оловоотсос. Оч рекомендую если надо изредка что-то отпаивать.
Оч клевый ручной оловоотсос. Оч рекомендую если надо изредка что-то отпаивать.

photo content

Помимо очевидных способов выстрелить себе в ногу на языке Си есть еще много совсем неочевидных, самые интересные: 1) думать что Си низкоуровневый язык близкий к железу 2) не отключать в компиляторе следование некоторым частям стандарта 3) надеяться на переносимость кода между версиями компилятора (хотя многие наверное уже стреляли этим способом в ногу) Шикарная статья про это все: http://cmustdie.com/

photo content

Today I Learned Можно увеличить выходной ток линейного регулятор добавлением резистора в параллель, но нагрузка должна кушать
+2
Today I Learned Можно увеличить выходной ток линейного регулятор добавлением резистора в параллель, но нагрузка должна кушать какой-то минимальный ток. Что и делали в древних схемах: https://www.maximintegrated.com/en/design/technical-documents/app-notes/3/3865.html

photo content

Сегодня очень простенькое про эмбед. Часто вижу вопросы "Как мне сделать так чтобы функцию прерывания не пришлось определять в моей библиотеке". У нас в флиппере довольно большая и сложная прошивка, которая требует в разные моменты времени разных функций-обработчиков прерываний. Это устроено следующим образом. Есть статический указатель на функцию:
typedef void (*FuriHalInterruptISR)();
volatile FuriHalInterruptISR furi_hal_tim_tim1_isr = NULL;

Есть функция которая устанавливает этот указатель:
void furi_hal_interrupt_set_timer_isr(TIM_TypeDef* timer, FuriHalInterruptISR isr) {
    if (timer == TIM1) {
        furi_hal_tim_tim1_isr = isr;
    }
}

И в функции прерывания мы просто вызываем этот указатель если он установлен:
/* Timer 1 Update */
void TIM1_UP_TIM16_IRQHandler(void) {
    if (furi_hal_tim_tim1_isr) {
        furi_hal_tim_tim1_isr();
    }
}

Это позволяет в любом месте программы установить вашу функцию в прерывание, не трогая сам код прерывания:
furi_hal_interrupt_set_timer_isr(TIM1, furi_hal_irda_tim_rx_isr);

И даже если нужно, очистить прерывание от выполнения вашей функции:
furi_hal_interrupt_set_timer_isr(TIM1, NULL);

ВАЖНО. Этот подход подразумевает что в момент установки\очистки прерывания соответствующая периферия выключена, так как установка указателя не атомарна. Функция которая была бы защищена от этого должна оборачивать код в критическую секцию, запрещая вызов прерываний:
void furi_hal_interrupt_set_timer_isr(TIM_TypeDef* timer, FuriHalInterruptISR isr) {
    __disable_irq();
    if (timer == TIM1) {
        furi_hal_tim_tim1_isr = isr;
    }
    __enable_irq();
}

Так же этот подход можно расширить на установку нескольких функций в одно прерывание, но тут уже возникают вопросы к быстродействию и организации списка функций. Если интересно — могу расписать примерные подходы в отдельном посте. Ознакомиться с полным кодом можно тут: https://github.com/flipperdevices/flipperzero-firmware/blob/dev/firmware/targets/f7/furi-hal/furi-hal-interrupt.c https://github.com/flipperdevices/flipperzero-firmware/blob/dev/firmware/targets/f7/furi-hal/furi-hal-interrupt.h

Лучший кроссовер
Лучший кроссовер

По мотивам вчерашнего обсуждения в https://t.me/theyforcedme/2895 Уточню что моя цель - писать код который легко поддерживать, дописывать и менять его логику, и это требование я выношу в основные. Довольно частая ситуация при написании программы - захват ресурса и освобождение его при выходе из функции. Для примера ресурса возьмем память. (тут и далее я прошу учитывать что я ограничен в объеме текста, и между захватом - освобождением ресурса вполне могут быть страница-две кода)
void foo(){
    // выделяем память
    DataType* data = malloc(sizeof(Data));

    // работаем с памятью
    process(data);

    // освобождаем память
    free(data);
}

Пока что все выглядит ок. Но требования меняются, и теперь нам надо обрабатывать данные в зависимости от того что вернула предыдущая обработка.
void foo(){
    DataType* data = malloc(sizeof(Data));

    if(process_1(data)){
        if(process_2(data)){
            if(process_3(data)){
                process_4(data);
            }
        }
    }

    free(data);
}

Цикломатическая сложность растет, и если мы продолжим писать в этом же стиле - рано или поздно мы уйдем ifами за правый край экрана (ну или запутаемся в блоках). Код становится неприятно читать и сложно поддерживать, давайте его перепишем на множественный возврат из функции.
void foo(){
    DataType* data = malloc(sizeof(Data));

    if(!process_1(data)){
        free(data);
        return;
    }

    if(!process_2(data)){
        free(data);
        return;
    }

    if(!process_3(data)){
        free(data);
        return;
    }

    process_4(data);

    free(data);
}

Это выглядит и читается приемлимо, но поддерживать этот код стало еще сложнее, например очень легко можно забыть освободить память перед возвратом. Для борьбы с этим человечество придумало блоки finally и идиому "Получение ресурса есть инициализация" (RAII). К сожалению мы любим простреленные ноги и пишем на языке Си, в котором подобное невозможно реализовать не превратив код обмазанный макросами в некрономикоподобный диалект. Что же мы можем сделать?
void foo(){
    DataType* data = malloc(sizeof(Data));

    if(!process_1(data)) goto finally;
    if(!process_2(data)) goto finally;
    if(!process_3(data)) goto finally;
    process_4(data);

    finally:
        free(data);
}

К сожалению столь лаконичный код получился с использованием goto. Использование оператора goto в целом критикуется, так как программу с его использованием читать на порядки сложнее, как минимум неявны начала и концы переходов, для подробной критики см "Go To Statement Considered Harmful" Эдсгера Дейкстры. Нам нужен блок который бы исполнялся один раз и из которого мы можем выйти оператором отличным от goto, например возьмем отдельную функцию.
void process_data(DataType* data){
    assert(data);
  
    if(!process_1(data)) return;
    if(!process_2(data)) return;
    if(!process_3(data)) return;
    process_4(data);
}

void foo(){
    DataType* data = malloc(sizeof(Data));
    process_data(data);
    free(data);
}

Приемлимый и поддерживаемый вариант, но требующий передачи ресурса в аргумент (а следовательно проверки аргумента) и требующий от программиста скакать по функциям, плюс загрязняющий область видимости. Чтобы не отвлекать программиста на другие функции мы можем использовать что-то наподобие "анонимной функции", например цикл из одной итерации. Цикл из одной итерации может быть любого вида, while, for, но do {} while (false); это довольно распространенная и понятная идиома, не требующая дополнительных переменных.
void foo(){
    DataType* data = malloc(sizeof(Data));

    do {
        if(!process_1(data)) break;
        if(!process_2(data)) break;
        if(!process_3(data)) break;
        process_4(data);
    } while(false);

    free(data);
}

В результате мы получили идиому которая явно указывает начало-конец перехода, выделяет блоком код который можно менять не отвлекаясь на освобождение ресурса, и в целом код который довольно лаконично выглядит.

Выкатил тут файловый менеджер для флиппера, не все работает, кнопки снизу не работают, терминал только для логов, не оптимизировано под мелкие дисплеи и в целом код грязноват, но уже можно загружать и скачивать файлы с\на флиппер. https://drzlo13.github.io/flipper-uwu-fileman/ UwU

Держите небольшое демо работы Флиппера с метками 125 кГц, а также пример записи на Т5577. Все эксперименты проводятся с капсулой, имплантированной мне в руку. У капсулы плохая антенна, так что запись происходит не моментально, но есть идеи, как улучшить это со стороны Флиппера.

photo content