Это список вопросов для тех кто числится программистом микроконтроллеров и занимается разработкой электроники. Вопросы в частности взяты из технических собеседований при устройстве на работу в разные реальные компании. Постарался отобрать только самые приближенные к практике вопросы, которые можно выделить после 10 лет InSider(ского) опыта. Тут не будет моветонных вопросов из серии "как инвертировать связанный список". Тут представлен обогащенный концентрат. Всё исключительно и только по делу.
По коду
1--Зачем static?
2--Зачем ключевое слово volatile C
3--Всё ли в порядке с кодом?
int square(volatile int *ptr) {
return *ptr * *ptr;
}
4--Может ли быть const volatile?
5--Зачем ключевое слово register?
6--Зачем ключевое слово restrict?
7--Зачем ключевое слово weak?
8--Зачем в С(ях) нужны битовые поля?
9--Зачем в С(ях) нужны объединения?
10--Как проверить, что в числе установлен/сброшен бит?
11--Как проверить, что два float числа равны между собой?
12--В какую память попадет глобальная переменная с ключевым словом const?
13--Какие есть способы передачи переменных в С функцию?
14--Есть ли способ запустить С-код до запуска main?
15--Что произойдет при компиляции этого участка кода?
const int MAX=100;
#if 100==MAX
#error "MAX:100"
#endif
int main(){
printf("MAX:%d",MAX);
return 0;
}
16--Зачем нужен препроцессорный #error?
17--Какое значение в локальной static переменной при первом вызове?
18--В чем недостаток inline функций?
19--Зачем нужен оператор препроцессора ##?
20--Как делать примитивы инкапсуляции в C?
21--Какие знаешь адекватные правила MISRA 2004 или MISRA 2012?
22--Как делать примитивы полиморфизма в С?
23--Напишите функцию, которая при передаче по аргументу значения 1 печатает "One". При передаче 2 печатает "Two". Запрещено использовать оператор if и оператор switch.
24--Может ли С функция во время исполнения определить, что ее вызвали рекурсивно?
25--Может ли C функция с переменным числом аргументов узнать сколько у нее аргументов?
26--Назови три способа вернуть массив из функции.
27--Зачем используют do{...} while(0); если это всего лишь 1 итерация?
28--Зачем нужен extern "C" ?
29--Напишете одной строчкой установку значения 0x11223344 по абсолютному адресу 0x20000016.
30--Что напечатается на экран?
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;
}
31--В чём разница между этими двумя прототипами?
uint16_t calc_crc16(uint8_t *inData, uint16_t const len);
uint16_t calc_crc16(uint8_t inData[], uint16_t const len);
32--Чему равен размер структур?
struct Foo {
int iiii;
char c;
};
struct record {
char tag;
unsigned index;
char has_extra_data;
char has_value;
int value;
};
33--Как упаковать структуру в компиляторе GCC?
34--Зачем нужны упакованный структуры кроме экономии RAM памяти?
35--Что напечатается в консоли при отработке функции
typedef struct{
int a:1;
int b;
}ab_t;
int main(void) {
ab_t ab;
ab.a = 1;
printf("%u" CRLF, ab.a);
return 0;
}
36--Чему равен 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);
37--Что вернет код?
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));
38--Какой код выполняется быстрее: первый или второй?
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]++;
}
}
}
39-- Есть константный Си-массив структур, который формируется препроцессором (cpp.еxe) до компиляции gcc из разных файлов проекта. Как проверить во время компиляции (до исполнения кода), что в финальном массиве структур нет повторяющихся элементов?
Системы сборки
40--Что такое система сборки?
41--Зачем использовать какую бы то ни было систему сборки (хоть GNU Make) если можно просто написать *.bat или *.sh скрипт который скармливает комилятору исходники? В cmd или bash скриптах же тоже есть переменные и условные операторы.
42--Чем система сборки Ninja отличается от системы сборки Make?
43-- Зачем в GNU Make нужно ключевое слово vpath?
Структуры данных
44--Чем циклический буфер отличается от FIFO?
45--Как удалить элемент из связанного списка не зная указателя не предыдущий элемент?
Про DevOps
46--Зачем собирать из скриптов, если всегда можно мышкой щелкнуть на зеленый треугольник в GUI-IDE?
47--Зачем нужны все эти сервера сборки типа Jenkins(а)?
48--Какие файлы следует подвергать версионному контролю в GIT?
49--Что для тебя значит рефакторинг? Что ты подразумеваешь под словом рефакторинг?
Про прерывания
50--Что такое прерывание?
51--Зачем нужны программные прерывания? Можно ведь просто функцию вызвать.
52--Что такое реентерабельная функция?
53--Сколько тактов процессора нужно для запуска возникшего прерывания на Cortex-M4?
54--Сколько тактов процессора нужно для вызова функции?
55--что такое таблица прерываний?
56--Каков алгоритм обработки прерываний? Что происходит во время срабатывания прерывания?
57--что такое вектор прерываний?
58--Какие есть внутренние прерывания?
59--Как регистр программного счетчика PC узнает куда возвращаться после обработки прерывания?
Про ToolChain
1--Как проверить что конкретный *.c или *.h файл вообще собирается?
2--Какой путь проходит Си-код с момента написания до попадания во flash память?
3--Как отключить/подавить какое-либо отдельное предупреждение компилятора GCC (например -Wrestrict)?
4--Компоновщик пишет, что прошивка не собирается из-за нехватки on-chip NOR-Flash памяти. Какие меры ты предпримешь, чтобы утрамбовать прошивку?
5--Что такое ABI (application binary interface)?
6--На какие сегменты разбита вся память прошивки? На какие сегменты разбита RAM память?
7--Какие доки(спеки) нужны для того, чтобы разрабатывать встраиваемый софт? Назовите минимум 4 дока.
8--Компилятору подали 5 *.с файликов и 20 *.h файликов. Сколько будет *.o файликов?
9--Тебе предоставили файл *.с чрезвычайно запутанный препроцессором. Как ты поймешь, что там происходит и в какой последовательности?
10--Что такое binutils? Какие знаете? Что можно с ними сделать?
11--Какие расширения файлов являются результатом работы разработчика MCU (артефакты)? Для чего нужен каждый из них?
12--В каких случаях артефакты в *.hex файликах предпочтительнее артефактов в *.bin файликах?
Вопросы про RTOS(ы)
1--Что такое Bare-Bone сборка RTOS прошивки?
2--Что такое поток?
3--что такое гонки в программах?
4--Что такое bit-banding и зачем нужен bit-banding?
5--Что такое контекст потока?
6--Что такое spinlock?
7--Что такое deadlock?
8--Что такое preemptive многозадачность?
9--Что такое критическая секция?
10--Что такое мьютекс?
11--Что такое семафор?
12--Пример атомарной операции?
13--Все ли в порядке в этом многопоточном коде?
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);
}
14--Что такое инверсия приоритетов?
15--Как бороться с инверсией приоритетов?
16--В стеке какого потока работают прерывания?
17--Что значит thread-safe код?
18--В чем разница между мьютекксом и семафором?
19--Что такое Reentrancy?
20--В чем разница между Joined и Detached потоками?
21--Написать функцию атомарного обмена содержимого переменных.
22--Что такое атомарные операции?
23--Как измерить процент загрузки MCU в прошивке без ОС?
Про цифровые фильтры:
24--В чём достоинство цифровых фильтров в отличие от аналоговых?
25--В чём недостаток FIR фильтра в сравнении с IIR фильтром?
26--Дан цифровой FIR фильтр. Иcходников нет, реализован в виде статической библиотеки *.a файла. Как узнать массив его коэффициентов B[0...N]?
27--Зачем в квадратурном смесителе нужно два смесителя (перемножителя), а не один, три или четыре?
Про железо (аппаратное обеспечение)
28--Чем резистор, конденсатор и катушки индуктивности отличаются друг от друга? В чём их сходство?
29--Каким напряжением открывается NPN транзистор?
30--Зачем микроконтроллерам функция Pull-Up/Pull-Down, если всегда можно включить LED просто установив логический уровень на GPIO?
31--Что такое PUSH-PULL, а что OPEN-DRAIN?
32--Как на 8MHz(цовом) микроконтроллере можно измерить частоту примерно 100MHz прямоугольного сигнала с GPIO?
33--Как проверить, что два PWM сигнала на 2х GPIO синфазные?
34--На одной SPI шине 2 Slave чипа. На оба подали одновременно Chip Select 0V и начали вычитывать регистры в которых разные данные. Что будет? Сгорит/не сгорит?
35--Какие регистры есть у микропроцессора ARM Cortex-M3 и для чего они нужны?
36--Что значит суперскалярный микропроцессор?
37--Почему частота часового кварца именно 32768 Hz?
38--Что нужно сделать программе с микроконтроллером, чтобы моргать светодиодом? Напишите словами каждый шаг.
39--Как сделать проверку-защиту, что firmware в самом деле предназначено именно для этой электронной платы?
40--По какому интерфейсу код взаимодействует с железом (ядром микроконтроллера)?
41--Что такое scatter/gather IO?
42--В чем отличия между архитектурами 8051, AVR, ARM, Xtensa, PowerPC, MIPS, RICS-V, x86, SPARC, ARC?
43--Что происходит с микроконтроллером между подачей питания и запуском функции main()?
44--Какие виды памяти есть в микроконтроллере.
45--На какие части обычно делится Flash память?
46--На какие части делится RAM память?
47--Как обрабатывать кнопку? Как преодолевать дребезг контактов?
48--Какой способ подключения LED предпочтительнее: a или b?
49--Дорисуйте блок-схему процессора ARM Cortex-M4 настолько, насколько вы в нем разбираетесь.
50-- Как при помощи микроконтроллера измерить сопротивление выводного резистора?
51-- Каким напряжением на затворе открывается P-channel MOSFET?
52--Зачем внутри микропроцессоров нужен MPU?
По интерфейсам
1--Какое напряжение на UART TX в режиме idle?
2--Зачем UART опция 2 стоповых бита, если это уменьшает data rate?
3--На шине SPI 2 разных чипа. На оба подали CS-0v и начали читать. Что произойдет: Сгорит/не сгорит/другое?
4--Как измерить процент загрузки CAN шины?
5--Какая разность потенциалов в CAN когда ничего не передается?
6--Есть два Lin интерфейса. У одного подтяжка data провода к 24V у другого подтяжка data провода к 12V. Data провода соединили. Что будет? Сгорит /не сгорит?
7--может ли i2c работать в режиме нескольких мастеров?
8--Чем CAN принципиально отличается от Ethernet?
9--У тебя на шине RS485 N устройств. Как мастер устройству узнать количество ведомых устройств на RS485 шине и их 32 битные адреса за минимальное время?
По протоколам
1--В каких протоколах у переменных big endian, а в каких протоколах у переменных little endian?
2--Зачем в TCP пакете контрольная сумма, если контрольная сумма есть в Ethernet пакете?
3--Зачем нужен IP-адрес, если уже есть MAC-адрес?
4--Как передавать пакеты по 1024 байт, если в PayLoad транспортного протокола помещается всего только 256 байт?
5--Почему CRC часто в конце пакета, а не в заголовке пакета?
6--Зачем нужно кодирование Base64 в Embedded?
7--Насколько процентов кодировка Base64 расширяет размер оригинального бинаря в самом худшем случае?
Вопросы про стек
1--Что происходит когда мы вызываем функцию?
2--Что хранится в стековой памяти?
3--Что такое стековый кадр? И что в нем хранится?
4--Какой код копирует в стек адрес возврата?
5--Можно ли на стеке выделить массив длинна которого задается аргументом функции?
6--Какой код копирует из стека адрес возврата из функции для регистра программного счетчика?
7--Кто инициализирует локальные переменные если их не проинициализирован явно ?
8--В какую сторону растет стек?
9--Сколько указателей стека в ARM Cortex-M4?
10--Что определяет в каком направлении будет расти стековая RAM память?
12--Какое значение в локальной переменной если ничего не присвоено при создании?
13--Что произойдет при переполнении стека?
14--Как определить на какую максимальную глубину заполнялась стековая память с момента запуска программы?
15--Все ли в порядке с функцией?
int8_t* foo(void) {
int8_t val=-5;
return (&val);
}
Беспроводные интерфейсы
--Как определить что передатчик в самом деле передает что-то?
--Нет радио Link(а) (например в LoRa). Как выявить в чем дело? Передатчик не передает или приемник не принимает?
Про heap память
--Как определить размер блока выделенного malloc?
--Как бороться с фрагментацией памяти?
--Как проверить сколько памяти выделено в куче в случайном месте программы?
Про загрузчики (Bootloader)
1--Зачем нужен загрузчик во встраиваемых системах? Назовите минимум 3 его функции.
2--Как загрузчик может обмениваться данными с приложением?
3--В чем опасность вызова функций загрузчика из приложения?
4--Как защитить микроконтроллер от загрузки чужеродного кода через загрузчик?
5--Как загрузчику понять, что загрузчик принял в самом деле прошивку, а не набор случайных циферок с правильной CRC?
6--Как сделать обновление прошивки по TCP/IP, если в загрузчике хватает NorFlash памяти только для драйвера UART?
7--Можно ли сделать так, чтобы загрузчик стартовал не с адреса начала Main Flash 0x0800_0000, а например с адреса 0x0806_0000?
8--Почему в микроконтроллерах STM32 секторы NOR Flash(а) разных размеров?
*9--Вам прислали прошивки в *.bin файле. Как загрузить и запустить эту прошивку по произвольному отступу в on-chip Nor Flash памяти?
10--Что код загрузчика должен сделать перед прыжком в приложения на ARM-Cortex-Mx?
*11--Каким образом кнопочные Siemens/Motorola/Nokia телефоны могли в run-time до устанавливать игры без пере прошивки микроконтроллера внутри?
Решение проблем (TroubleShooting)
1--Тебе дали дорогую плату запрограммировать прямо с производства. Плату ещё ни разу не включали в питание. Крайне вероятно, что плата сгорит при первом же включении из-за брака монтажа. Как ты проверишь плату не испортив ценный полуфабрикат?
2--Прошивка зависла, ваши действия?
3--Какие утечки вы знаете кроме утечки памяти?
4--Прошивка после подачи питания постоянно и непрерывно перезагружается. Как вы станете это ремонтировать?
5--Ты пишешь код, собираешь, запускаешь и вдруг прошивка перезагружается. Твои действия?
6--Как отладить большой кусок кода, если нет возможности пройти JTAG/SWD отладчиком?
7--Какие меры увеличения надежности софта предлагает стандарт ISO-26262?
8--По ходу добавления функционала вы столкнулись с нехваткой RAM памяти для своих глобальных переменных. Как отобразить всё глобальные переменные одной командой в консоли?
9--По ходу добавления функционала вы столкнулись с нехваткой ROM памяти. Как отобразить все функции одной командой в консоли?
10--Зачем мультиметру функция True RMS?
11--Что такое полоса пропускания в осциллографе?
Вопросы для развернутого устного ответа (System Design)
7--Как из одного потока передать массивы разных размеров другому потоку без динамического выделения памяти?
1--Как можно реализовать энергонезависимую Key-Val Map(ку) на микроконтроллере?
2--Как померить процент загрузки микроконтроллера в конкретное время (прошивка NoRTOS)?
3--Как можно реализовать надежную доставку пакетов поверх протокола UDP?
4--Как бы ты реализовал механизм FOTA? Т.е. обновления прошивки по беспроводному интерфейсу (Bluetooth, WiFi, LoRa, RFID, UWB и т.п.)?
5--У тебя на шине RS485 N устройств. Как мастер устройству узнать количество ведомых устройств на RS485 шине и их 32 битные MAC адреса за минимальное время?
6--Чем конечный автомат Мура отличается от конечного автомата Мили?
Вопросы для проверки навыков пользования компьютером
1--Есть текстовый файл-лог размером 50Mbyte. Строки с ошибками обозначены как [E]. Как узнать есть ли в логе ошибки и сколько их?
2--Диск переполнился. Комп тормозит. Как быстро выяснить размер каждой папки?
3--Как из консоли рекурсивно открыть в Notepad++ все файлы с расширение *.mk?
4--Как рекурсивно удалить все файлы расширения *.bak?
5--Что такое регулярные выражения?
6--Как отобразить все 3-буквенные слова в текстовом файле?
7--Напиши bash команду, которая ищет во всех файлах папки проекта макрос с под именем "LED" только в файлах board.h
8--Как в папке открытой в консоли рекурсивно заменить слово old_word на new_word во всех фалах внутри папки
Вопросы со звездочкой *
1--Как измерить покрытие микроконтроллерного кода после отработки модульных тестов?
2--Опиши как работает JTAG под капотом (установка точки останова).
3--Почему на некоторых MCU RAM память не является непрерывной, а разделена на несколько отдельный непрерывных диапазонов адресов?
4--Как узнать время сборки каждого *.с файла?
5--Как рассчитать CRC на стадии компиляции, чтобы положить результат в константный массив?
6--Как добавить еще одну отладочную кнопку, если уже все пины заняты.
7--Какой путь проходят данные с момента излучения с GNSS спутника до выхода в NMEA протоколе GNSS приемника?
Вопросы на способность тестирования и отладки
1--Какие существуют способы отлаживать прошивки? Назовите как минимум 10 способов.
2--Какой самый сложный программный или аппаратный баг приходилось искать и починить?
3--Как перезагрузить прошивку? Перечислите как можно больше способов. Минимум 3 способа.
4--Для чего нужны модульные тесты (скрепы)? Назовите 2+ причины.
5--Как отобразить UART лог в коде, который отрабатывает до инициализации отладочного UART?
6--Сколько способов подключить 4 провода к 8 ми клеммникам? Речь идет про конец каждого провода. В один клеммник устанавливается только 1 конец провода.
7--Как избежать чрезмерного, избыточного количества модульных тестов?
8--Как проверить, что инфракрасный передатчик IR в самом деле излучает хоть что-то?
9--Как проверить, что два массива это перестановка одних и тех же чисел?
10--Как протестировать драйвер графического I2C дисплея c SSD1306 в режиме write only?
11--Компания разработала прошивку для научного калькулятора выражения из строчки (типа Cassio FX-991EX). Придумай минимальное количество тестовых строчек, чтобы протестировать этот научный калькулятор .
№ | Входная строчка | Ожидаемый результат |
1 | "(2+3)*2" | 10 |
2 | "1.5/0.0" | Math Error |
3 | ")(" | Syntax Error |
Варианты для тестового задания дома
1--Напишите функцию для вычисления угла между 2D векторами с учетом знака (правая тройка).
2--Напишите функцию, которая вычисляет PWM sample.
double pwm_sample_calc(uint64_t time_us,
double freq,
double cur_phase_ms,
double des_amplitude,
double duty_cycle,
double offset);
3--Напишите прошивку под STM32F4, которая генерирует на GPIO два аппаратных PWM с возможностью менять фазу, частоту, скважность через UART в run-time.
*4--Напишите энергонезависимую FlashFS(NVRAM) для, например, STM32 микроконтроллера. Предусмотрите endurance optimization и защиту данных от пропадания питания.
5--Напишите heap allocator или попросту реализуйте malloc() free().
6--Даны две GNSS координаты. Вычислить азимут в градусах. Покрыть тестами.
7--Напишите минималистичную прошивку STM32 загрузчика (MBR), которая только прыгает в определенный адрес (например 0x08016000), чтобы запустить приложение. Постарайтесь уместить *.bin файл в 1kByte. У кого меньше бинарь, тот и победил.
8--В микроконтроллерной системе аналого-цифровой преобразователь измеряет напряжение на канале. Это напряжение надо конвертировать в дискретный уровень, в зависимости от значения. Сигнал зашумлен. Надо реализовать программный гистерезис. Напишите функцию, которая выполнит эту работу. Используйте в вычислениях только целочисленные типы.
int hysteresis(unsigned int input_percent);
9--Напишите диагностическую утилиту интерпретатор 19ти 8ми битных регистров RTC чипа DS3231. Регистровый dump считывать из текстового файла.
10*--Напишите Си функцию-переходник, которая преобразует PDM сигнал с MEMS микрофона в PCM сэмплы для загрузки в интерфейс I2S.
11--Напишите Cи-функцию csv_parse_text, которая выделяет из Comma-separated values строки текст по индексу. Вот модульный тест для csv_parse_text.
bool test_csv_parse_text(void){
LOG_INFO(TEST, "%s():", __FUNCTION__);
bool res = true;
set_log_level(CSV, LOG_LEVEL_DEBUG);
char sub_text[80] = "";
memset(sub_text, 0, sizeof(sub_text));
EXPECT_TRUE( csv_parse_text(";;c;;",';', 2, sub_text, sizeof(sub_text)));
EXPECT_STREQ("c", sub_text);
EXPECT_TRUE( csv_parse_text("ll wm8731 debug;ll i2c debug;tsr 127",';', 0, sub_text, sizeof(sub_text)) );
EXPECT_STREQ("ll wm8731 debug", sub_text);
EXPECT_TRUE( csv_parse_text("ll wm8731 debug,ll i2c debug,tsr 127",',', 1, sub_text, sizeof(sub_text)) );
EXPECT_STREQ("ll i2c debug", sub_text);
EXPECT_TRUE( csv_parse_text("ll wm8731 debug|ll i2c debug|tsr 127",'|', 2, sub_text, sizeof(sub_text)) );
EXPECT_STREQ("tsr 127", sub_text);
set_log_level(CSV, LOG_LEVEL_INFO);
return res;
}
12--Написать Си-функцию, которая распознает вещественное число из строчки. То есть универсальный парсер типа данных double. Вот несколько тест кейсов: "." -> 0.0; ".5" -> 0.5; "5." -> 5.0; " 6" -> 6.0; "+1e2" -> 100; " 1/3" -> 0.33;
13--Написать Си-функцию, которая берёт произвольную строку и распознает минимальный тип данных для информации в этой строке. Написать код согласно требованиям ISO26262-6
# теста | Строка на входе | распознанный тип данных |
1 | '1' | uint8_t |
2 | '-20' | int8_t |
3 | 'some_text' | string |
4 | '3.14' | double |
5 | '0x12345678' | uint32_t |
6 | '0x1234567878563412' | uint64_t |
7 | 'a' | char |
8 | '0x1234' | uint16_t |
9 | '1.56e-1' | double |
10 | '1/3' | string |
Если Вы знаете адекватные, сложные и интересные вопросы по теме разработки на MCU, то пишите их в комментариях.