Не удалось прочитать идентификатор через SWD с помощью Arduino.
Итак, я пытаюсь прочитать немного данных через SWD. В качестве целевых я попробовал две микросхемы - LPC1110 и STM32F030F4 (первую из них я использовал для другой схемы, но я перезагрузил флэш-память, чтобы убедиться, что контакты не настроены неправильно).
Я использую Arduino в качестве хоста. Я подключаю D3 к SWCLK и D4 к SWDIO (с подтягиванием до линии 3,3 В). Я терплю неудачу с обоими чипами - то есть, когда я ожидаю, что какой-то ACK будет прочитан - он все время показывает только ВЫСОКОЕ состояние на линии.
Вот мой код. Может ли кто-нибудь посмотреть и сказать, где я ошибся:
int swdck = 3;
int swdio = 4;
void setup() {
pinMode(swdck, OUTPUT);
digitalWrite(swdck, HIGH);
pinMode(swdio, INPUT);
digitalWrite(swdio, HIGH);
Serial.begin(9600);
}
// записываем несколько битов из X (сначала наименее значимый) в SWD
void clockOut(int x, int bits) {
pinMode(swdio, OUTPUT);
while (bits > 0) {
digitalWrite(swdck, LOW);
digitalWrite(swdio, (x & 1) ? HIGH : LOW);
delay(1);
digitalWrite(swdck, HIGH);
delay(1);
bits--;
x >>= 1;
}
pinMode(swdio, INPUT);
digitalWrite(swdio, HIGH);
}
// читаем некоторые биты из SWD, сначала наименее значимые
int clockIn(int bits) {
pinMode(swdio, INPUT);
digitalWrite(swdio, HIGH);
int i, res;
res = 0;
for (i = 0; i < bits; i++) {
digitalWrite(swdck, LOW);
delay(1);
if (digitalRead(swdio) == HIGH) {
res += (1 << i);
}
digitalWrite(swdck, HIGH);
delay(1);
}
return res;
}
void loop() {
int x;
// последовательность разблокировки, хотя, вероятно, она не нужна
clockIn(26); clockIn(26); // более 50 часов
clockOut(0xE79E, 16); //команда переключения на SWD
clockIn(26); clockIn(26);
clockOut(0x25, 7); // 0b0100101 - запрос на чтение Debug-port-0, т.е. ID
x = clockIn(5); // где-то должны быть биты ACK... но я получаю 0x1111
clockIn(26); clockIn(26); // выполняем дополнительные чтения на случай, если что-нибудь будет возвращено
Serial.println(x);
delay(1000);
}
@Alumashka, 👍0
Обсуждение1 ответ
Я не эксперт по SWD; прошло несколько лет с тех пор, как я читал спецификацию. Так что прошу прощения, если вы меня опередили.
Я полагаю, что в документации SWD от ARM, например, «ARM® Debug Interface v5 Architecture Specification» (ARM IHI 0031A), говорится, что передачи имеют фиксированную длину, начиная с 8-битного запроса.
Код:
void clockOut(int x, int bits) {
pinMode(swdio, OUTPUT);
while (bits > 0) {
...
bits--;
...
}
...
}
вызывается с помощью clockOut(0xE79E, 16)
Запрос пакета — это 8 бит, за которыми следует ответ от цели. Так что это, похоже, не соответствует протоколу.
Аналогично clockOut(0x25, 7)
, похоже, отправляет 7 бит, что также выглядит неправильно и может объяснять, почему чтение не удается.
Кроме того, после отправки пакета должен быть «бит возврата».
Этот код:
void clockOut(int x, int bits) {
pinMode(swdio, OUTPUT);
...
pinMode(swdio, INPUT);
digitalWrite(swdio, HIGH);
}
Похоже, он готовится к этому, однако ему также необходимо подать сигнал о другом тактовом импульсе, например:
void clockOut(int x, int bits) {
pinMode(swdio, OUTPUT);
...
pinMode(swdio, INPUT);
digitalWrite(swdio, HIGH);
/* signal a clock pulse */
digitalWrite(swdck, LOW);
delay(1);
digitalWrite(swdck, HIGH);
delay(1);
}
Чтение SWD должно возвращать 33 бита, поэтому x = clockIn(5);
выглядит немного хрупким.
Даже в этом случае он должен получить три бита ACK. Он должен оставить еще одну кучу битов непрочитанными, что я и имею в виду под хрупкостью.
Однако x = clockIn(5);
может быть неверным из-за короткого clockOut(0x25, 7)
и отсутствия бита возврата.
Небольшие замечания:
- Я бы изменил этот цикл
clockOut
while
на циклfor
, например,clockIn
, чтобы было ясно, что он выполняется для определенного «количества» (бит) бит, которые необходимо передать. delay(1)
кажется, это долгое время между битами. Я не помню никаких Ограничения по времени. Однако я бы ожидал, что переводы будут выполняться В 10–100 раз быстрее.- ИМХО
clockIn(26); clockIn(26);
кажется излишне запутанным способом для создания 50-цикловой последовательности соединения/сброса. Я бы, наверное, немного более простая функция, чемclockIn
, которая только генерирует последовательность подключения/сброса.
Редактировать:
Оператор res += (1 << i);
в clockIn
работает.
Однако мне пришлось прочитать его пару раз, чтобы понять, что он собирает двоичное значение, а не выполняет какую-то сложную арифметику. Чаще всего для сборки двоичного значения используются побитовые операторы. Это всего лишь небольшая деталь стиля, однако res |= (1 << i);
может более четко создавать двоичное значение, чем res += (1 << i);
, потому что он может повлиять только на один бит и никогда на много битов.
Спасибо за развернутый ответ! Постараюсь ответить пошагово. Запрос SWD — это 8 бит, да, но последний бит «не должен управляться хостом на swdio», т. е. в этот момент хост должен отключить вывод и просто отправить еще один такт. Я предполагаю, что это выполняется внутри clockIn(5). Вот почему у меня здесь 5 — я хочу отправить несколько тактов, чтобы любой бит парковки, бит поворота и ack тактировались одновременно. Если придет любое другое значение, кроме 0x1F, я надеюсь, что смогу угадать, где в нем ACK..., @Alumashka
Что касается 0xE79E - я считаю, что это вообще не часть протокола SWD, просто какая-то магическая последовательность для переключения с JTAG на SWD (и есть обратная последовательность переключения). Я понятия не имею, нужна ли она этим чипам, поэтому я тестировал с ней и без нее. В любом случае, видите ли, я сам почти ничего не знаю о SWD - я только пару дней назад начал читать руководства... Так что, конечно, я могу ошибаться в чем угодно или во всем. Также спасибо за ценные рекомендации по стилю/дизайну!, @Alumashka
- Как объявить массив переменного размера (глобально)
- Программирование Arduino с использованием Python, а не C/C ++
- Загрузка Arduino Nano дает ошибку: avrdude: stk500_recv(): programmer is not responding
- Как справиться с rollover millis()?
- Является ли использование malloc() и free() действительно плохой идеей для Arduino?
- Можно ли сделать несколько функций loop() с помощью Arduino Uno?
- Какие накладные расходы и другие соображения существуют при использовании структуры по сравнению с классом?
- устаревшее преобразование из строковой константы в 'char*'
Пожалуйста, опубликуйте объяснение того, как контакты ARM-MCU питаются только до 3,3 В, а не 5 В. Я предполагаю, что это правильно, и в своем ответе я рассмотрел только программное обеспечение. Тем не менее, было бы полезно быть уверенным в булавках., @gbulmer
Ваше беспокойство верно, но похоже, что оба чипа ARM, которые я использовал (LPC и STM32), имеют входы, устойчивые к 5 В. С другой стороны, когда логический сигнал 3,3 В подается на вход TTL, он также превышает пороговое значение, поэтому все работает нормально. Похоже, производители чипов принимают такие меры предосторожности, чтобы избавить людей от изобретения интерфейсных схем..., @Alumashka
Я не читал внимательно спецификации LPC, поэтому очень полезно знать, что у них есть контакты SWD, устойчивые к 5 В (возможно, даже стоит обновить ваш вопрос, чтобы упомянуть об этом). Мне интересны ваши результаты. У вас это работает?, @gbulmer