Это список вопросов на которые должен уметь ответить тот кто программирует микроконтроллеры и заниматься разработкой электроники. Вопросы в частности взяты из технических собеседований при устройстве на работу в разные компании. Постарался отобрать только самые приближенные к практике вопросы, которые можно выделить после 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<NN; j++){
for(i=0; i<NN; i++){
Amatrix[i][j]++;
}
}
}
void inc_matrix_ij(void) {
int i=0,j=0;
for(i=0;i<NN;i++){
for(j=0;j<NN;j++){
Amatrix[i][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 0x0800_0000, а например с адреса 0x0806_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), которая только прыгает в определенный адрес (например 0x08016000), чтобы запустить приложение. Постарайтесь уместить *.bin файл в 1kByte.
Если вы знаете адекватные, сложные и интересные вопросы по теме разработки на MCU, то пишите их в комментариях.
Автор:
aabzel