Коллоквиум по программированию микроконтроллеров

0c021e67269c256b6e7392de9c52b735.png

Это список вопросов на которые должен уметь ответить тот кто программирует микроконтроллеры и заниматься разработкой электроники. Вопросы в частности взяты из технических собеседований при устройстве на работу в разные компании. Постарался отобрать только самые приближенные к практике вопросы, которые можно выделить после 10 лет InSider (ского) опыта. Тут не будет моветонных вопросов из серии «как инвертировать связанный список». Тут всё исключительно только по делу.

По коду

--Зачем static?

--Зачем ключевое слово volatile C

--Всё ли в порядке с кодом?

int square(volatile int *ptr) {
    return *ptr * *ptr;
}

--Может ли быть const volitile?

--Зачем ключевое слово register?

--Зачем ключевое слово restrict?

--Зачем ключевое слово weak?

--Как проверить, что в числе установлен/сброшен бит?

--Как проверить, что два float числа равны между собой?

--В какую память попадет глобальная переменная с ключевым словом const?

--Какие есть способы передачи переменных в С функцию?

--Есть ли способ запустить С-код до запуска main?

--Что произойдет при компиляции этого участка кода?

const int MAX=100;
#if 100==MAX
#error "MAX:100"
#endif

int main(){
   printf("MAX:%d",MAX);
   return 0;
}

--Зачем нужен препроцессорный #error?

--Какое значение в локальной static переменной при первом вызове?

--Зачем нужен оператор препроцессора ##?

--Как делать инкапсуляцию в C?

--Как делать примитивы полиморфизма в чистом С?

--Может ли С функция во время исполнения определить, что ее вызвали рекурсивно?

--Может ли C функция с переменным числом аргументов узнать сколько у нее аргументов?

--Назови три способов вернуть массив из функции.

--Зачем используют do{…} while (0); если это всего лишь 1 итерация?

--Зачем нужен extern «C»?

--Что напечатается на экран?


int main() {
    char str5[]={'s','t','r','i','n','g'};
    printf("\n5 %s size: %d len:%d",str5, sizeof(str5), strlen(str5));
  
    char *str1="string";
    printf("\n1 %s size: %d len:%d",str1, sizeof(str1), strlen(str1));
  
    const char *str2="string";
    printf("\n2 %s size: %d len:%d",str2, sizeof(str2), strlen(str2));
  
    char str3[]="string";
    printf("\n3 %s size: %d len:%d",str3, sizeof(str3), strlen(str3));
  
    char str4[10]="string";
    printf("\n4 %s size: %d len:%d",str4, sizeof(str4), strlen(str4));
  
    char *str6=strdup("string");
    printf("\n6 %s size: %d len:%d",str6, sizeof(str6), strlen(str6));
  
    char *str7=(char[]){"string"};
    printf("\n7 %s size: %d len:%d",str7, sizeof(str7), strlen(str7)); 
    return 0;
}

--В чём разница между этими двумя прототипами?

uint16_t calc_crc16(uint8_t *inData, uint16_t const len); 
uint16_t calc_crc16(uint8_t inData[], uint16_t const len); 

--Чему равен размер структур?

struct Foo {
    int iiii;
    char c;
};

struct record {
    char tag;
    unsigned index;
    char has_extra_data;
    char has_value;
    int value;
};

--Чему равен val? Значение необходимо указать исходя из типа памяти little endian и проще выразить в hex формате

    uint16_t arr[4] = {0x04,0x03,0x02,0x01};
    uint32_t val;
    val = *((uint32_t*) (&arr[1]));
    printf("val=%08x \n", val);

--Что вернет код?

static char *val_2_str(int i){
    static char buff[10];
    snprintf(buff,sizeof(buff)," %d ",i);
    return buff;
}

printf("\n%s %s",val_2_str(3),val_2_str(4));

Какой код выполняется быстрее

void inc_matrix_ji(void) {
    int i=0,j=0;
    for(j=0; j

Структуры данных

--Чем циклический буфер отличается от FIFO?

--Как удалить элемент из связанного списка не зная указателя не предыдущий элемент?

Про DevOps

--Зачем собирать из скриптов, если всегда можно мышкой щелкнуть на зеленый треугольник в IDE?

--Зачем нужен сервер сборки Jenkins?

--Какие файлы следует подвергать версионному контролю в GIT?

--Что для тебя значит рефакторинг?

Про прерывания

--Что такое прерывание?

--Зачем нужны программные прерывания? Можно ведь просто функцию вызвать.

--Что такое реентабельная функция?

--что такое таблица прерываний?

--Каков алгоритм обработки прерываний? Что происходит во время срабатывания прерывания?

--что такое вектор прерываний?

--Какие есть внутренние прерывания?

--Как регистр PC узнает куда возвращаться после обработки прерывания?

Про ToolChain

--Как проверить что .c или .h файл вообще собирается?

--Какой путь проходит код с момента написания до попадания в flash память?

--Что такое ABI (application binary interface)?

--На какие сегменты разбита память прошивки?

--Какие доки нужны для того, чтобы программировать встраиваемый софт?

--Компилятору дали 5*. с файлов и 20*. h файлов. Сколько будет*. o файлов?

--Тебе предоставили файл *.с чрезвычайно запутанный препроцессором. Как ты поймешь, что там происходит и в какой последовательности?

--Что такое binutils? Какие знаете? Что можно с ними сделать?

--Какие файлы являются результатом работы разработчика MCU (артефакты)?

Про RTOS (ы)

--Что такое поток?

--что такое гонки в программах?

--Что такое bit-banding и зачем нужен bit-banding?

--Что такое контекст потока?

--Что такое spinlock?

--Что такое deadlock?

--Что такое preemptive многозадачность?

--Что такое критическая секция?

--Что такое мьютекс?

--Что такое семафор?

--Пример атомарной операции?

--Все ли в порядке в этом многопоточном коде?

DataA a;
DataB b;
DataC c;

mutex ma, mb, mc;

void TaskA(){
    lock(ma);
    lock(mb);
    // use a, b
    unlock(mb);
    unlock(ma);
}

void TaskB(){
    lock(mb);
    lock(mc);
    lock(ma);
    // use a, b, c
    unlock(ma);
    unlock(mb);
    unlock(mc);
}

void TaskC(){
    lock(mc);
    // use c
    unlock(mc);
}

--Что такое инверсия приоритетов?

--Как бороться с инверсией приоритетов?

--В стеке какого потока работают прерывания?

--Что значит thread-safe код?

--В чем разница между мьютекксом и семафором?

--Что такое Reentrancy?

--В чем разница между Joined и Detached потоками?

--Написать функцию атомарного обмена содержимого переменных.

--Что такое атомарные операции?

--Как измерить процент загрузки MCU в прошивке без ОС?

Про железо

--Как на 10MHz (цовом) микроконтроллере можно измерить частоту примерно 100MHz прямоугольного сигнала с GPIO?

--Что такое PUSH-PULL, а что OPEN-DRAIN?

--На одной SPI шине 2 Slave чипа. На оба подали одновременно Chip Select 0V и начали вычитывать регистры в которых разные данные. Что будет? Сгорит/не сгорит?

--Какие есть регистры у Cortex M3 и для чего они нужны?

--Что значит суперскалярный микропроцессор?

--Почему частота часового кварца именно 32768 Hz?

--Есть два Lin интерфейса. У одного подтяжка к 24V у другого подтяжка к 12V. Их соединили. Что будет? Сгорит /не сгорит?

--Что нужно сделать программе с микроконтроллером, чтобы моргать светодиодом? Напишите словами каждый шаг.

--Как проверить, что 2 прямоугольных сигнала на 2х GPIO синфазные?

--Как сделать проверку-защиту, что firmware в самом деле предназначено именно для этой платы?

--По какому интерфейсу код взаимодействует с железом (ядром микроконтроллера)?

--Что такое scatter/gather IO?

--В чем отличие ARM от PowerPC?

--Что происходит с микроконтроллером между подачей питания и запуском функции main ()?

--Какие виды памяти есть в микроконтроллере.

--На какие части обычно делится Flash память?

--На какие части делится RAM память?

--В чем достоинство цифровых фильтров в отличие от аналоговых?

--Как обрабатывать кнопку? Как преодолевать дребезг контактов?

По интерфейсам

--Какое напряжение на UART TX в режиме idle?

--Зачем UART опция 2 стоповых бита, если это уменьшает data rate?

По протоколам

--В каких протоколах у переменных big endian, а в каких протоколах у переменных little endian?

--Зачем в TCP контрольная сумма если контрольная сумма есть в Ethernet пакете?

--Зачем нужен IP-адрес, если есть MAC-адрес?

--Почему CRC часто в конце пакета, а не в заголовке?

Вопросы про стек

--Что хранится в стековой памяти?

--Что такое стековый кадр? И что в нем хранится?

--Какой код копирует в стек адрес возврата?

--Какой код копирует из стека адрес возврата из функции для регистра программного счетчика?

--Кто инициализирует локальные переменные если их не проинициализирован явно ?

--В какую сторону растет стек?

--Сколько указателей стека в ARM Cortex-M4?

--Что определяет в каком направлении будет расти стековая RAM память?

--Какое значение в локальной переменной если ничего не присвоено при создании?

--Что произойдет при переполнении стека?

--Как определить на какую максимальную глубину заполнялась стековая память с момента запуска программы?

--Все ли в порядке с функцией?

int8_t* foo(void) {
    int8_t val=-5;
    return (&val);
}

Беспроводные интерфейсы

--Как определить что передатчик в самом деле передает что-то?

--Нет радио Link (а) (например в LoRa). Как выявить в чем дело? Передатчик не передает или приемник не принимает?

Про heap память

--Как определить размер блока выделенного malloc?

--Как бороться с фрагментацией памяти?

--Как проверить сколько памяти выделено в куче в случайном месте программы?

Про загрузчики

--Как загрузчик может обмениваться данными с приложением?

--В чем опасность вызова функций загрузчика из приложения?

--Как защитить микроконтроллер от загрузки чужеродного кода через загрузчик?

--Как загрузчику понять, что загрузчик принял в самом деле прошивку, а не набор случайных циферок с правильной CRC?

--Как сделать обновление прошивки по TCP/IP, если в загрузчике хватает NorFlash памяти только для драйвера UART?

--Можно ли сделать так, чтобы загрузчик стартовал не с адреса начала Main Flash 0×0800_0000, а например с адреса 0×0806_0000?

--Почему в микроконтроллерах STM32 секторы разных размеров?

Решение проблем (TroubleShooting)

--Тебе дали дорогую плату запрограммировать прямо с производства. Плату ещё ни разу не включали в питание. Крайне вероятно, что плата сгорит при первом же включении из-за брака монтажа. Как ты проверишь плату не испортив ценный полуфабрикат?

--Прошивка зависла, ваши действия?

--Какие утечки вы знаете кроме утечки памяти?

--Прошивка после подачи питания постоянно и непрерывно перезагружается. Как вы станете это ремонтировать?

--Ты пишешь код, собираешь, запускаешь и вдруг прошивка перезагружается. Твои действия?

--Как отладить большой кусок кода, если нет возможности пройти JTAG/SWD отладчиком?

Вопросы для развернутого устного ответа

--Как можно реализовать энергонезависимую Key-Val map на микроконтроллере?

--Как померить процент загрузки микроконтроллера в конкретное время (прошивка NoRTOS)?

Вопросы для проверки навыков пользования компьютером

--Есть текстовый файл-лог размером 50Mbyte. Строки с ошибками обозначены как [E]. Как узнать есть ли в логе ошибки и сколько их?

--Диск переполнился. Комп тормозит. Как быстро выяснить размер каждой папки?

--Как из консоли рекурсивно открыть в Notepad++ все файлы с расширение *.mk?

--Как рекурсивно удалить все файлы расширения *.bak?

--Как отобразить все 3-буквенные слова в текстовом файле?

--Напиши bash команду, которая ищет во всех файлах папки проекта макрос с под именем «LED» только в файлах board.h

Вопросы со звездочкой *

--Как измерить покрытие микроконтроллерного кода после отработки модульных тестов?

--Опиши как работает JTAG под капотом (установка точки останова).

--Почему на некоторых MCU RAM память не является непрерывной, а разделена на несколько отдельный непрерывных диапазонов адресов?

--Как узнать время сборки каждого *.с файла?

--Как рассчитать CRC на стадии компиляции, чтобы положить результат в константный массив?

--Как добавить еще одну отладочную кнопку, если уже все пины заняты.

Вопросы на способность тестирования и отладки

--Какие существуют способы отлаживать прошивки? Назовите как минимум пять способов.

--Какой самый сложный программный или аппаратный баг приходилось искать и починить?

--Как перезагрузить прошивку? Перечислите как можно больше способов. Минимум 3 способа.

--Сколько способов подключить 4 провода к 8 ми клеммникам?

--Как избежать чрезмерного, избыточного количества модульных тестов?

--Как проверить, что инфракрасный передатчик IR в самом деле излучает хоть что-то?

--Как проверить, что два массива это перестановка одних и тех же чисел?

Варианты для тестового задания дома

--Напишите функцию для вычисления угла между 2D векторами с учетом знака (правая тройка).

--Напишите функцию, которая вычисляет PWM sample.

double pwm_sample_calc(uint64_t time_us, 
                       double freq, 
                       double cur_phase_ms,
                       double des_amplitude, 
                       double duty_cycle, 
                       double offset);

--Напишите прошивку под STM32F4, которая генерирует на GPIO два аппаратных PWM с возможностью менять фазу, частоту, скважность через UART в run-time.

--Напишите энергонезависимую FlashFS для STM32F микроконтроллера. Предусмотрите endurance optimization и защиту данных от пропадания питания.

--Напишите heap allocator или попросту реализуйте malloc () free ().

--Даны две GNSS координаты. Вычислить азимут в градусах. Покрыть тестами.

--Напишите минималистичную прошивку STM32 загрузчика (MBR), которая только прыгает в определенный адрес (например 0×08016000), чтобы запустить приложение. Постарайтесь уместить *.bin файл в 1kByte.

Если вы знаете адекватные, сложные и интересные вопросы по теме разработки на MCU, то пишите их в комментариях.

© Habrahabr.ru