forked from prudy/mtpoe_ctrl
-
Notifications
You must be signed in to change notification settings - Fork 0
/
ATtiny-x.txt
308 lines (287 loc) · 27.9 KB
/
ATtiny-x.txt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
В микротиках для POE используется микроконтроллер Atmel ATtiny 461a
Это 8 битный микроконтрорллер. К устройству он подсоединен посредством шины SPI.
Итак CLK, MOSI, MISO я у него нашел. Остается вопрос: где Slave Select пин и к какому GPIO ЦП он подключен?
Гугление про реализацию SPI Slave на ATtiny микроконтроллерах вот что дало:
https://weathergadget.wordpress.com/2016/05/19/usi-spi-slave-communication/
On the slave side, I need to use two interrupts. One interrupt (PCINT0) to have the slave in SPI mode
(slave select aka. chip select) and a second interrupt (USI_OVF), which gets triggered when a frame was
transferred. It works like a cascade, the second interrupt gets armed and disarmed by the first interrupt.
Armed if the pin recognizes a falling edge and disarmed, when recognizes a rising edge.
Из спецификации SPI шины понятно что микросхема Slave считается выбранной когда на ее SS пине появляется
сигнал LOW! Пока сигнал HIGH она не должна реагировать на передающиеся по SPI шине данные т.к. они не для нее!
Поиск по датащиту ATtiny 461a на предмет строчки Slave Select:
The USI Three-wire mode is compliant to the Serial Peripheral Interface (SPI) mode 0 and 1, but
does not have the slave select(SS) pin functionality. However, this feature can be implemented
in software if necessary!
Итак судя из все той же статьи: https://weathergadget.wordpress.com/2016/05/19/usi-spi-slave-communication/
для подключения(у них ATtiny85!) в режиме SPI Slave они использовали следующие пины:
PB0 - DI - MOSI
PB1 - DO - MISO
PB2 - USCK - CLK
PB3 - CS - SS - Chip Select!
На PB3(CS и он же SS) ставится обработчик прерывания!
Для нашей ATtiny 461a пины для MOSI, MISO и CLK точно такие же: PB0, PB1, PB2. Логично предположить что
Chip Select должен быть PB3? Это пин 2: Левая боковая грань, второй если считать с верху в низ.
Но нет.
PB3 - управляет транзистором Q708
PB4 - управляет транзистором Q704
PB5 - - управляет транзистором Q706
PB6 и PB7 - а вот эти подключены к ножкам ЦП !!! К каким я не выяснил. Нужно дергать GPIO и смотреть!
Учитывая что PB7 это еще и Reset ! A low level on this pin for longer than the minimum pulse length
will generate a reset ! The reset pin can also be used as a (weak) I/O pin !
Так что похоже что наш Chip Select это PB6! Нужно подключать логический анализатор к PB6 и смотреть
что на нем !!! Ну и PB7 порассматривать!!!
.
PB6 оказался Chip Select. Как я и думал! Это GPIO12 !
PB7 это Reset. Это GPIO14 ! На нем всегда 1! Если отключить gpio то будет 0. Думаю этот пин где то подтянут на
VCC. В общем в нормальном состоянии на него можно забить. Его нужно делать 0 только для перепрошивки
мокроконтроллера.
И GPIO12 и GPIO14 я проверил логическим анализатором и подпаиванием тонких проволочек к чипу.
Они без проблем доступны и переключаются в 0 и обратно в 1.
.
https://habr.com/post/152052/ - отличная статья как переводить в режим перепрошивки и шить ATtiny
микроконтроллеры! Перевод делается через пин RESET !
.
PA0 и PA1 через конденсаторы смотрят на землю!
Расковырял микротик прошивку. Вот что имеем:
Итак модуль управления пое называется poe_v2.ko. Там есть срочка rb700-spi-attiny.
Так же есть модуль poeupdate.ko ! Он нужен (только!) для обновления прошивки Attiny!
В частности в poeupdate есть строчка "attiny-reset" и там дергается gpio который называется attiny-reset.
Предположительно в зависимости от платформы его номер ???? берется из вызова hw_options?
А так же есть бинарник poeupdatefw который вызывается из /etc/rc.d/run.d/S03poeupdate
и заливает в контроллер прошивку /etc/poeio.atflash
То есть таки всем рулит poe_v2!
Итак исходя из этой статьи http://georgekontopidis.com/blog/2012/modify-mikrotik-rb-750up-to-measure-any-voltage/
входное напряжение меряется на пине ADC1. Там оно относительно питания чипа(3.3V) и чип в шину SPI
выдает его попугаях от 0 до 1024! ADC1 выведен на кондер который самый ближний к чипу с низу(напротив PA5-PA7 ног)
Там напряжение получается через делитель!
Итого имеем следующее. Чип на запрос по SPI:
MOSI: 0x42 0 0 0x7E 0 0 0 0 0 0
отвечает:
MISO: 0 0 0 0 0x7E 0x42 0x2 0xA3 0xA2 0xA2 -> 23.6V ->
где 0x2A3 это собственно напряжение на аналоговом вхоже ADC1 в попугаях(0...1024) относительно 3.3V.
В частности при ADC1 = 0.846V я получал значение 259!(вместо 263). Т.к. в самом чипе напряжение падает
на ~ 0,013 и фактически на анализатор напряжения в чипе приходит 0,833V ! что как раз и соответствует 259 !
Для примера рассчитаем сколько вольт будет для 0x02A3(что в примере выше):
0x02A3 -> 675:
675 - Xv
1024 - 3.3v
Xv = 3.3 * 675 / 1024 = 2,1753 что соответствует 23.6V. Коэфициент 10.8. Микротик немного округляет!
Плюс сам делитель напряжения может плыть! Так что на разных девайсах показания немного разнятся. Нужна калибровка
путем подключения тестера!
Остается вопрос - что за последние два байта(0xA2 0xA2). Они имеют одно и тоже значение относительно друг друга!
Я предполагаю что это CRC ? Только вот какая?
На сайте https://crccalc.com/ он показывает все возможные CRC алгоритмы(большую их часть).
Итак я предпологаю что это CRC8.
Изучение кода в IdaPro для poe_v2.ko показало что там есть ф-я (я назвал ее calc_crc) вызываемая из ф-и выдающей
сообщения вида "POE rx crc error, retry\n". Так вот в коде этой ф-и(она маленькая, написана с использованием
регистров и одного цикла. видно что она что то обсчитывает побайтово!) видно что она работает с тремя
байтами! Основная ф-я видимо ждет данных полученных по spi и вызывает calc_crc чтобы их проверить.
Итак я предположил что для нашего ответа для 'B' - напряжение получается следующее:
ответ: 0x7E 0x42 0x01 0x38 0xC6 0xC6 - CRC как видишь 0xС6
три байта у нас 0x42 0x1 0x38
получаем что алгоритм подсчета CRC-8 Dallas/Maxim ! Все пойманные блоки показали что это именно этот алгоритм!
Ф-я для подсчета этого алгоритма: https://stackoverflow.com/questions/29214301/ios-how-to-calculate-crc-8-dallas-maxim-of-nsdata
Аналогично запрос 0x42 0x00 0x00 0x7E - тут 0x7E это CRC-8 Dallas/Maxim по трем первым байтам(0x42 0x00 0x00)
Так что и запрос и ответы защищены CRC!
Итого: Запрос всегда 4 байта! Ответ может быть переменной длины! Но в нашем случае его можно принять как 6 байт!
Вот такие у нас есть команды для контроллера Attiny(poe v2)(запрос/<TAB> ответ)
'A' - 0x41 0 0 0x9A - ХЗ ! - запрос версии прошивки?
0x9A 0x41 0x02 0x11 0xC8 0xC8
'B' - 0x42 0 0 0x7E - запрос входного напряжения
0x7E 0x42 0x01 0x38 0xC6 0xC6
'C' - 0x43 0 0 0xD5 - запрос температуры
0xD5 0x43 0x01 0x25 0xD 0xD
'D' - 0x44 0x04 0 0x94 - запрос на отключение POE на порту ether2
0x94 0x44 0x04 00 0x94 0x94
'D' - 0x44 0x03 0 0xFA - запрос на отключение POE на порту ether3
0xFA 0x44 0x03 00 0xFA 0xFA
'D' - 0x44 0x02 0 0x3E - запрос на отключение POE на порту ether4
0x3E 0x44 0x02 00 0x3E 0x3E
'D' - 0x44 0x01 0 0x6B - запрос на отключение POE на порту ether5
0x6B 0x44 0x01 00 0x6B 0x6B
'E' - 0x45 0x00 0x00 0x04 - получение статуса POE портов
04 45 11 11 EF EF - все порты включены! по единичке(в десятичной системе) на каждый порт!
0=off, 1=force-on, 2=auto-on
'F' - 0x46 0x01 0x00 0x24 - хз. но когда пое включено в режим auto-on хотябы на одном порту роутер ось ее
0x24 0x46 0x01 0x00 0x24 0x24. Видимо пинает ATtiny чтобы он проверил статус auto-on портов?!?
auto-on мутная штука. она и на роутер оси глючит! лучше ее не использовать!
начинает выполнять с периодичностью в 6 сек!
'G' - 0x47 0xAA 0 0x42 - команда зеркало??? какие параметры отправишь - такие и получишь в ответ!
0x42 0x47 0xAA 0 0x42 0x42
'H' - 0x48 0x01 0x23 0x11 - проверка статуса пое/или жимости самого ATtiny ??? одно и тоже возвращает постоянно!!!
0x11 0x48 0x01 0x23 0x11 0x11
'Y' - 0x59 00 00 CRC - запрос статуса POE на ether5. так же возвращает ток в миллиамперах.
'Z' - 0x5A 00 00 CRC - запрос статуса POE на ether4
'[' - 0x5B 00 00 CRC - запрос статуса POE на ether3
'\' - 0x5C 00 00 CRC - запрос статуса POE на ether2
Например для ether2(poe off):
запрос: 0x5C 0x00 0x00 0xC0 - последний байт 0xC0 как обычно контрольная сумма
ответ: 0xC0 0x5C 0x80 0x00 0xEF 0xEF - пое отключено(off)! так же если порт в состоянии auto-on
то 0x80 означает waiting for load! при этом следующий за ним байт может быть > 0 !
Фактически нужно 8-й бит проверять на == 1. если он 1 то пое off или waiting-for-load.
Если он 0 то есть нагрузка!
Так же для ether2 при force-on и отсутствии нагрузки возвращается значение FF FF
Видимо схемотехника для ether2 немного отличается!
При появлении нагрузки значения такие же как и остальных портов 0x xx
Для остальных портов там 00 xx(10-11mA)
Для ether2 и auto-on по прежнему возвращает 0x80 как и должно быть.
При КЗ(short-citcuit) он возвращает 0x80 0x0A. 0x80 соответственно что подача питания отключена
а 0x0A что КЗ(short-citcuit). КЗ отрабатывает мгновенно. Даже искры не успевают полететь!
Без шума и пыли так сказать! Да и при КЗ контроллер сразу вырубает пое на ~ВСЕХ~ портах!
А потом запускает те на которых нет КЗ!
Например для ether5(poe on. потребление 76-77mA):
запрос: 0x59 0x00 0x00 0xF5
ответ: 0xF5 0x59 0x00 0x4F 0xF2 0xF2 - 0xF2 0xF2 контрольная сумма. потребление := 0x004F.
При этом текущее напряжение(poe-out-voltage) оно тупо узнает командой 'B' ! и уже исходя из напряжения
и потребления(в Амперах) рассчитывает мощность(в Ваттах)!
Таблица соответствий между миллиамперами и байтами(вторым байтом. первый при мелких нагрузках всегда 00)
5mA - 0x05
6mA - 0x06
12mA - 0x0С
13mA - 0x0D
119mA - 0x77
То есть ток в миллиамперах тупо возвращаеют как есть - числом!
При загрузке РоутерОС имеем следующую последовательность команд:
'A' - 0x41 - запрос версии?
'B' - 0x42 - запрос входного напряжения
'C' - 0x43 - запрос температуры
'G' - 0x47 - ???
'D' - 0x44 - серия команд 'D': отключение/включение POE на портах. Хотя порты и так в этом состоянии.
Перестраховывается?
Как я не искал но команду 'E' я не нашел в запросах! ХЗ как роутер ось узнает о статусе пое портов!
а она и не узнает! она тупо смотрит свои настройки и при буте переводит порты в эти настройки
(как она счинает что они должны быть!) Так что если ты поменяешь настройки пое для портов в своей
прошивке и потом загрузишь роутер ось то она перезапишет настройки пое в Attiny на те что у нее
сохранены на флешке! То есть умность контроллера в плане запоминания настроек не используется!
Думаю эта умность нужна только для плавильного бута чтобы до старта роутер ос подалось питание
на нужное оборудование. ну а потом роутер ось еще раз все пое настройки перезаписывает!
Но как видишь команда 'E' для получения статуса портов все таки оставлена!
Рассмотрим подробно команду 'D' - 0x44
'D' - 0x44 0x01 0x01 0x35 - запрос на включение/отключение POE на порту.
0x35 0x44 0x01 0x01 0x35 0xCA ... 0xCA 0x35
1: 0x44 это номер команды.
2: 0x01-0x04 это номер порта. причем порты зеркально отражены(4-й это 1-й и т.д.)
3: 0x01 или 0x0 - 0x1=force-on или 0x0=off или 0x2=auto-on
4: 0x35 это CRC-8 Dallas.
auto-on это умный режим. контроллер сам определяет есть ли потребление на порту и включает питание если
оно там есть! то есть когда к порту что то подключено!
Ответ прилетает тоже интересный.
1: 0x35 это нам вернули контрольную сумму посчитанную по 3-м байтам параметром которые мы им отправили!
2: 0x44 - номер команды на которую получен ответ
3: 0x01 - номер порта
4: 0x01 или 0x0 - вкл или выкл.
5: 0x35 - опять CRC от 3 байт ответа. Дальше идет поток из 0xCA ... 0xCA
6: 0xCA для on port5 и 0x11 для port5 off, 0x9F для on port4, и 0xC1 для off port4
эти байты идут по ~ 50 штук. Это инвертированные 8 бит от CRC! ( то есть: 0xCA это:
11001010 а 0x35 это 00110101 ! Видимо оно их шлет пока идут переходные процессы и порт переключает режим
питания!
7: 0x35 - в самом конце опять идет наша контрольная сумма! Нам как бы дают знать что все готово.
6-й и 7-й байты можно опустить если сразу после команды вырубить(установить в HIGH) сигнал CS.
Это короткая форма когда нам не нужно знать когда именно пое применит нашу команду!?!
При ините контроллера во время бута роутер ос так и делает а вот при ручном изменении она долго
держит сигнал поднятым и эти байты летят! Видимо чтобы убедиться что пока пое не будет переключено
следующапя комакнда не начнет выполняться!?!
после команды 'D' - 0x44 вызывается команда 'H' - 0x48 0x01 0x23 0x11. Ее предназначение я пока не понял.
Видимо проверка статуса пое. Она всегда возвращает одно и тоже
Так же важно помнить что контроллер запоминает статус пое портов. Если их включили то они будут включены при
сделующей подаче питания! Даже до загрузки ОС! И если я со своей прошивки их включаю то РоутерОСь загрузившить
видит что они включены!
Считывание статуса poe портов: вкл/выкл:
****** SPI и Linux ******
Читаем https://habr.com/post/123145/ и https://habr.com/post/123266/
Теперь попробуем с OpenWRT пообщаться с нашим контроллером.
Период ф-и CLOCK == 0.5 микро секунд. На сколько я могу понимать это 2 мгц частоты!
Итак режим работы SPI == MODE_0(CPOL = 0, CPHA=0). В статье выше описано как это определить. Да и Saleae Logic
бы не прочитал данные если бы режим был выставлен не верно. Просто тебе повезло что MODE_0 самый распространенный!
Отправка и прием команд по SPI работает. Но есть странность. Пришлось понизить частоту до 15Khz.
Если внимательно посмотреть на график CLOCK обмена РоутерОСИ с ATtiny То видно что оно отправляет 8 бит
на скорости в 2 мгц а потом идет пробел в 15.04Khz(66.25 микро секунд!) то есть контроллеру дают время на подумать?
И если мы все передаем на 15 Khz то ясное дело контроллер успевает! Похожая проблема описана тут:
https://raspberrypi.stackexchange.com/questions/73649/raspberry-pi-spi-and-interbyte-delay
As you can see, there is interbyte spacing between the individual bytes. The MLX90316 needs a bit of time
to fill the last 2 MISO bytes with the sensor value, after seeing the 0x55 in the first byte.
spidev просто не умеет такого. Даже есть патчик который это делает:
https://groups.google.com/forum/#!topic/linux-sunxi/61CJ4tFaGMQ
В общем я пока решил оставить работу на 8Khz. Это дает задержку между байтами в 72 микро секунды.
Это конечно занимает шину и все такое но данных у меня передается мало и из за этого искать как пропатчить
spidev + драйвер ar79_spi я не буду! для sunxispi видно что есть спец регистр который позволяет аппаратно
реазиловать эту задержку! хз есть ли такой же для ar79_spi!
.
update at 2021-04-23:
В новой версии OpenWRT(v21) обновили spi драйвер. Теперь он вместо тупого ногодрыга использует регистр spi контроллера для
передачи сразу 32-х бит. Соответственно из за аппаратных ограничений минимальная частота работы шины стала ~ 2Mhz
и мой подход с замедлением шины до 8Khz просто перестал работать! Ногодрыгу то было все равно, с какой скоростью ногами дрыгать.
Пришлось реализовывать описанный выше подход с interbyte spacing. Для этого я сделал патч нового spi драйвера:
0052-spi-add-interbyte-spacing-delay-to-ar934x.patch и отправил его автору драйвера.
Этот патч передает не сразу 32 бита а 8 бит(на частоте указанной для устройства - в моем случае это 2 Мгц) а после этого ждет
заданный word_delay_usecs(micro seconds) и передает следующие 8 бит. И это работает! Собственно у микротика изначально было
так же(про это я писал выше).
Перевод ATtiny в режим перепрошивки:
согласно датащиту: http://ww1.microchip.com/downloads/en/DeviceDoc/doc8197.pdf
и вот этому: https://habr.com/post/152052/
!!!!!!!!!!!!!!!!
данные по spi шине для других устройств в это время передаваться не должны!
так что лучше загрузиться через netboot и не активировать gpio расширитель лампочек !
!!!!!!!!!!!!!!!!
echo 0 > /sys/class/gpio/gpio14/value - подаем низкий уровень на RESET pin ATtiny.
mtpoe_ctrl --action=raw_send --raw_hex_val="AC 53 00 00" - Programming Enable
{
action: "raw_send",
tx: "0xAC 0x53 0x00 0x00",
rx: "0x00 0x00 0x53 0x00" - 0x53 это ответ!
}
mtpoe_ctrl --action=raw_send --raw_hex_val="30 00 00-02 00" - три раза. получаем ID чипа.
}
rx: "0x00 0x30 0x00 0x1E"
rx: "0x00 0x30 0x00 0x92"
rx: "0x00 0x30 0x00 0x08"
}
то есть ID нашего чипа: 0x1E 0x92 0x08 что соответствует ATtiny461
Значит чип в режиме перепрошивки!
mtpoe_ctrl --action=raw_send --raw_hex_val="58 00 00 00"
{
action: "raw_send",
tx: "0x58 0x00 0x00 0x00",
rx: "0x00 0x58 0x00 0xFC"
}
то есть Lock bits := 0xFC
читаем тут: https://ph0en1x.net/100-what-is-fuse-and-lock-bits-in-avr-microcontroller-howto.html#what-is-fuse-lock-bits-avr
11111100 - LB1(запись), и LB2(чтение) биты установлены( == 0 !) так что перезапись внутренней eeprom и flash памяти запрещена!
так же запрещено ее чтение!
Вот почему команды "20 00 00 00" и "28 00 00 00" возвращают 0xFF!
Выход только один - отдать команду: Chip Erase: "AC 80 00 00" которая сбросит защитные биты и сотрет всю память!
и затем шыть чип заново! Да и после прошивки не плохо было бы вернуть на место значения Lock и Fuse bits.
Сейчас они такие:
Lock bits read: "58 00 00 00" := 0xFC
Read Fuse bits: "50 00 00 00" := 0xE1
Read Fuse High bits: "58 08 00 00" := 0xC5
Read Extended Fuse Bits: "50 08 00 00" := 0xFF
для того чтобы понять какая размерность флеша(сколько страниц, размер страницы), а так же как задается
адресация можно смотреть вот сюда: https://github.com/SpenceKonde/ATTinyCore/blob/master/avr/avrdude.conf
итого для ATtiny 461a имеем следующее:
Flash size: 2K words (4K bytes), Page size: 32 words, No. of Pages: 64
Load Program Memory Page:
40 000xxxxx xxxbbbbb iiiiiiii - low word byte
48 000xxxxx xxxbbbbb iiiiiiii - high word byte
Write Program Memory Page - 4C xxxxxaaa bbbxxxxx xxxxxxxx
Записи по Mikrotik PoE V3.
Итак на rb960 пое гигабитное и представлено оно в виде микросхемы ATmel ATSAMD20J15. Это многоногий микроконтрлллер.
Тоже подключен по SPI. ChipSelect gpio назначать не нужно, видимобутлоадер при загрузке поединяет нужный
gpio с spi контроллером. Кстати это CS2 ! При том что 0-й это флешка а 1-го устройства на шине вроде бы НЕТ.
.
0x41 0 0 0x9A - ХЗ ! - запрос версии прошивки
БЫЛО(v2): 0x9A 0x41 0x02 0x11 0xC8 0xC8 - 2.17
СТАЛО(V3): 0xFF 0x41 0x40 0x0C 0xA2 0xA2 - 64.12
0x42 0 0 0x7E - запрос входного напряжения
БЫЛО(v2): 0x7E 0x42 0x01 0x38 0xC6 0xC6
СТАЛО(V3): 0xFF 0x42 0x09 0x8E 0x5F 0x5F - 24.4V
0x43 0 0 0xD5 - запрос температуры
БЫЛО(v2): 0xD5 0x43 0x01 0x25 0xD 0xD
СТАЛО(V3): 0xFF 0x43 0x02 0xDB 0x33 0x33 - 51C
Соответственно старые формулы пересчета в вольты и градусы перестали работать!
Вывел новые. Управление портами продолжило работать без изменений. А вот статус портов(0, 1, 2) изменил порядок
портов в 2-х байтах результата.
Так же немного изменился и сам формат ответа на все команды. Там больше не передается CRC8 которую мы пепредали
в запросе. В общем если интересны все изменения - смотри git diff.
Для отладки удобно использовать команду: mtpoe_ctrl --action=raw_send --raw_hex_val="41 00 00 9A 00 00 00 00 00 00" --poe_proto=3