Jump to content

    

xelax

Свой
  • Content Count

    369
  • Joined

  • Last visited

Community Reputation

0 Обычный

About xelax

  • Rank
    Местный
  • Birthday 01/31/1980
  1. Убрал опцию --use_frame_pointer, вернул вложенные прерывания, оставил максимальную оптимизацию --O3. Hard fault исчезли. Вернул опцию, буквально несколько секунд и софт падает в Hard fault. Спасибо, судя по всему, действительно идет некорректная работа со стеком с включенной опцией.
  2. Да мы действительно используем --use_frame_pointer. r11 как раз компилятором отводится под frame pointer. Можно поподробней о некорректном выходе из функции? есть какая-нибудь errata или ссылка на описание проблемы? И оптимизацию зачем выключать? Мы без нее на финальном этапе проекта не влезем в размер памяти, отведенный нам по ТЗ.
  3. К сожалению objdump трактует r11 как fp. Не знаю, это Keil делает. Показать в каком коде происходит hard fault. Возможно разговор пойдет предметный, а не абстрактный. нет мы не переключаем в PSP, работаем в MSP. Ось не используем.
  4. Сразу хочу извиниться дизасм сделал гнусным objdump, так как кейловским fromelf пользоваться не очень умею. В принципе разницы быть не должно, так как исходный файл в elf формате. hard fault был после вызова по адресу 1324c, так как в r0 была ересь, которая попала туда из r5. Самое примечательное, что до той строчки внутри функции все было ок, то есть в r5 ереси не было. Сама функция uart_irq_handler является прерывание, но с низким приоритетом, то есть ее вытеснить и испоганить r5 могло только прерывание с высоким приоритетом. r5 нигде не пишется кроме адреса 13174. Сам код собственно даже не наш, а взят из SDK Nordic. #if defined(UART_IN_USE) __STATIC_INLINE void uart_irq_handler() { 13170: e92d 4bff stmdb sp!, {r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, fp, lr} if (nrf_uart_int_enable_check(NRF_UART0, NRF_UART_INT_MASK_ERROR) && 13174: 4d43 ldr r5, [pc, #268]; (13284 <uart_irq_handler+0x114>) } #if defined(UART_IN_USE) __STATIC_INLINE void uart_irq_handler() { 13176: f10d 0b2c add.w fp, sp, #44; 0x2c if (nrf_uart_int_enable_check(NRF_UART0, NRF_UART_INT_MASK_ERROR) && 1317a: f44f 7100 mov.w r1, #512; 0x200 1317e: 4628 mov r0, r5 13180: f7fc f920 bl f3c4 <nrf_uart_int_enable_check> 13184: 2701 movs r7, #1 nrf_uart_event_check(NRF_UART0, NRF_UART_EVENT_ERROR)) { nrf_drv_uart_event_t event; nrf_uart_event_clear(NRF_UART0, NRF_UART_EVENT_ERROR); nrf_uart_int_disable(NRF_UART0, NRF_UART_INT_MASK_RXDRDY | NRF_UART_INT_MASK_ERROR); if (!m_cb.rx_enabled) 13186: 4c40 ldr r4, [pc, #256]; (13288 <uart_irq_handler+0x118>) if (nrf_uart_int_enable_check(NRF_UART0, NRF_UART_INT_MASK_ERROR) && nrf_uart_event_check(NRF_UART0, NRF_UART_EVENT_ERROR)) { nrf_drv_uart_event_t event; nrf_uart_event_clear(NRF_UART0, NRF_UART_EVENT_ERROR); nrf_uart_int_disable(NRF_UART0, NRF_UART_INT_MASK_RXDRDY | NRF_UART_INT_MASK_ERROR); 13188: f44f 7801 mov.w r8, #516; 0x204 1318c: 2600 movs r6, #0 #if defined(UART_IN_USE) __STATIC_INLINE void uart_irq_handler() { if (nrf_uart_int_enable_check(NRF_UART0, NRF_UART_INT_MASK_ERROR) && 1318e: b318 cbz r0, 131d8 <uart_irq_handler+0x68> nrf_uart_event_check(NRF_UART0, NRF_UART_EVENT_ERROR)) 13190: f44f 7192 mov.w r1, #292; 0x124 13194: 4628 mov r0, r5 13196: f7fc f907 bl f3a8 <nrf_uart_event_check> 1319a: b1e8 cbz r0, 131d8 <uart_irq_handler+0x68> 1319c: f8c5 6124 str.w r6, [r5, #292]; 0x124 131a0: f8c5 8308 str.w r8, [r5, #776]; 0x308 { nrf_drv_uart_event_t event; nrf_uart_event_clear(NRF_UART0, NRF_UART_EVENT_ERROR); nrf_uart_int_disable(NRF_UART0, NRF_UART_INT_MASK_RXDRDY | NRF_UART_INT_MASK_ERROR); if (!m_cb.rx_enabled) 131a4: 7ea0 ldrb r0, [r4, #26] 131a6: b900 cbnz r0, 131aa <uart_irq_handler+0x3a> 131a8: 606f str r7, [r5, #4] { nrf_uart_task_trigger(NRF_UART0, NRF_UART_TASK_STOPRX); } event.type = NRF_DRV_UART_EVT_ERROR; 131aa: 2002 movs r0, #2 131ac: f80b 0c2c strb.w r0, [fp, #-44] 131b0: f8d5 0480 ldr.w r0, [r5, #1152]; 0x480 131b4: f8c5 0480 str.w r0, [r5, #1152]; 0x480 event.data.error.error_mask = nrf_uart_errorsrc_get_and_clear(NRF_UART0); 131b8: f84b 0c20 str.w r0, [fp, #-32] event.data.error.rxtx.bytes = m_cb.rx_buffer_length; 131bc: 7de0 ldrb r0, [r4, #23] 131be: f80b 0c24 strb.w r0, [fp, #-36] event.data.error.rxtx.p_data = m_cb.p_rx_buffer; 131c2: 68e0 ldr r0, [r4, #12] 131c4: f84b 0c28 str.w r0, [fp, #-40] //abort transfer m_cb.rx_buffer_length = 0; 131c8: 75e6 strb r6, [r4, #23] m_cb.rx_secondary_buffer_length = 0; 131ca: 7626 strb r6, [r4, #24] m_cb.handler(&event,m_cb.p_context); 131cc: e9d4 1200 ldrd r1, r2, [r4] 131d0: f1ab 002c sub.w r0, fp, #44; 0x2c 131d4: 4790 blx r2 } 131d6: e024 b.n 13222 <uart_irq_handler+0xb2> else if (nrf_uart_int_enable_check(NRF_UART0, NRF_UART_INT_MASK_RXDRDY) && 131d8: 2104 movs r1, #4 131da: 4628 mov r0, r5 131dc: f7fc f8f2 bl f3c4 <nrf_uart_int_enable_check> 131e0: b1f8 cbz r0, 13222 <uart_irq_handler+0xb2> nrf_uart_event_check(NRF_UART0, NRF_UART_EVENT_RXDRDY)) 131e2: f44f 7184 mov.w r1, #264; 0x108 131e6: 4628 mov r0, r5 131e8: f7fc f8de bl f3a8 <nrf_uart_event_check> 131ec: b1c8 cbz r0, 13222 <uart_irq_handler+0xb2> { rx_byte(); 131ee: f7fe f89b bl 11328 <rx_byte> if (m_cb.rx_buffer_length == m_cb.rx_counter) 131f2: 7de0 ldrb r0, [r4, #23] 131f4: 7e61 ldrb r1, [r4, #25] 131f6: 4288 cmp r0, r1 131f8: d113 bne.n 13222 <uart_irq_handler+0xb2> { if (m_cb.rx_secondary_buffer_length) 131fa: 7e22 ldrb r2, [r4, #24] 131fc: b13a cbz r2, 1320e <uart_irq_handler+0x9e> { uint8_t * p_data = m_cb.p_rx_buffer; uint8_t rx_counter = m_cb.rx_counter; 131fe: 7e60 ldrb r0, [r4, #25] 13200: 68e1 ldr r1, [r4, #12] //Switch to secondary buffer. m_cb.rx_buffer_length = m_cb.rx_secondary_buffer_length; 13202: 75e2 strb r2, [r4, #23] m_cb.p_rx_buffer = m_cb.p_rx_secondary_buffer; 13204: 6922 ldr r2, [r4, #16] m_cb.rx_secondary_buffer_length = 0; 13206: 60e2 str r2, [r4, #12] 13208: 7626 strb r6, [r4, #24] m_cb.rx_counter = 0; 1320a: 7666 strb r6, [r4, #25] rx_done_event(rx_counter, p_data); } 1320c: e007 b.n 1321e <uart_irq_handler+0xae> else { if (!m_cb.rx_enabled) 1320e: 7ea0 ldrb r0, [r4, #26] 13210: b900 cbnz r0, 13214 <uart_irq_handler+0xa4> 13212: 606f str r7, [r5, #4] 13214: f8c5 8308 str.w r8, [r5, #776]; 0x308 { nrf_uart_task_trigger(NRF_UART0, NRF_UART_TASK_STOPRX); } nrf_uart_int_disable(NRF_UART0, NRF_UART_INT_MASK_RXDRDY | NRF_UART_INT_MASK_ERROR); m_cb.rx_buffer_length = 0; 13218: 75e6 strb r6, [r4, #23] rx_done_event(m_cb.rx_counter, m_cb.p_rx_buffer); 1321a: 7e60 ldrb r0, [r4, #25] 1321c: 68e1 ldr r1, [r4, #12] //Switch to secondary buffer. m_cb.rx_buffer_length = m_cb.rx_secondary_buffer_length; m_cb.p_rx_buffer = m_cb.p_rx_secondary_buffer; m_cb.rx_secondary_buffer_length = 0; m_cb.rx_counter = 0; rx_done_event(rx_counter, p_data); 1321e: f7fe f8a3 bl 11368 <rx_done_event> rx_done_event(m_cb.rx_counter, m_cb.p_rx_buffer); } } } if (nrf_uart_event_check(NRF_UART0, NRF_UART_EVENT_TXDRDY)) 13222: f44f 718e mov.w r1, #284; 0x11c 13226: 4628 mov r0, r5 13228: f7fc f8be bl f3a8 <nrf_uart_event_check> 1322c: b158 cbz r0, 13246 <uart_irq_handler+0xd6> { if (m_cb.tx_counter < (uint16_t) m_cb.tx_buffer_length) 1322e: 8aa1 ldrh r1, [r4, #20] 13230: 7da0 ldrb r0, [r4, #22] 13232: 4281 cmp r1, r0 13234: d202 bcs.n 1323c <uart_irq_handler+0xcc> { tx_byte(); 13236: f7ff fea1 bl 12f7c <tx_byte> 1323a: e004 b.n 13246 <uart_irq_handler+0xd6> 1323c: f8c5 611c str.w r6, [r5, #284]; 0x11c } else { nrf_uart_event_clear(NRF_UART0, NRF_UART_EVENT_TXDRDY); if (m_cb.tx_buffer_length) 13240: b108 cbz r0, 13246 <uart_irq_handler+0xd6> { tx_done_event(m_cb.tx_buffer_length); 13242: f7ff feb5 bl 12fb0 <tx_done_event> } } } if (nrf_uart_event_check(NRF_UART0, NRF_UART_EVENT_RXTO)) 13246: f44f 71a2 mov.w r1, #324; 0x144 1324a: 4628 mov r0, r5 1324c: f7fc f8ac bl f3a8 <nrf_uart_event_check> 13250: 46dd mov sp, fp 13252: 2800 cmp r0, #0 13254: b08b sub sp, #44; 0x2c 13256: d013 beq.n 13280 <uart_irq_handler+0x110> 13258: f8c5 6144 str.w r6, [r5, #324]; 0x144 { nrf_uart_event_clear(NRF_UART0, NRF_UART_EVENT_RXTO); // RXTO event may be triggered as a result of abort call. In th if (m_cb.rx_enabled) 1325c: 7ea0 ldrb r0, [r4, #26] 1325e: b100 cbz r0, 13262 <uart_irq_handler+0xf2> 13260: 602f str r7, [r5, #0] { nrf_uart_task_trigger(NRF_UART0, NRF_UART_TASK_STARTRX); } if (m_cb.rx_buffer_length) 13262: 7de0 ldrb r0, [r4, #23] 13264: 46dd mov sp, fp 13266: 2800 cmp r0, #0 13268: b08b sub sp, #44; 0x2c 1326a: d009 beq.n 13280 <uart_irq_handler+0x110> { m_cb.rx_buffer_length = 0; 1326c: 75e6 strb r6, [r4, #23] rx_done_event(m_cb.rx_counter, m_cb.p_rx_buffer); 1326e: 7e60 ldrb r0, [r4, #25] 13270: 68e1 ldr r1, [r4, #12] 13272: b004 add sp, #16 13274: e8bd 4bf0 ldmia.w sp!, {r4, r5, r6, r7, r8, r9, fp, lr} 13278: f7fe b876 b.w 11368 <rx_done_event> 1327c: 46dd mov sp, fp 1327e: b08b sub sp, #44; 0x2c } } } 13280: e8bd 8bff ldmia.w sp!, {r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, fp, pc} 13284: 40002000 .word 0x40002000 13288: 200011d8 .word 0x200011d8 На стек 1024 байта выделили, так что по идее должно хватить, тем более модель памяти держим сходящуюся. Глобальные переменные с одного края памяти, стек с другого, так что даже при превышении размера стека, проедем по неиспользуемой памяти. Ассемблерные вставки не используем.
  5. Исходные данные. Код для cortex-m4 (nrf52), язык С, компилятор Keil. Ситуация следующая. В принципе все ок и работает. Работаем в основном с GCC, но по условиям ТЗ код должен собираться и работать также на IAR и Keil, так что периодически билдим и запускаем код на них. GCC и IAR работают без проблем. Keil падает в hard fault в рандомном месте. Первые подозрения были на проезды по памяти. Детальное исследование одного из падений показало, что hard fault случается так как портится значение в регистре общего назначения r5, который используется компилятором внутри функции как базовый адрес для работы с периферией. Внутри функции r5 не обновляется (записывается константа при входе в функцию один раз). То есть предположение проезда по памяти отпадает. Второе предположение что поведение ломают вложенные прерывания подтвердилось. Сделали все прерывания одинакового приоритета hard fault исчез. Вроде как баг исчез и стоит порадоваться, но очень похоже на черную магию, так как логического объяснения такому поведению не можем дать. Сохранение регистров в стек и восстановление везде присутствует (как минимум тщательно проверил сохранение\восстановление контекста в функции где упал в hard fault и тела высокоприоритетного прерывания). Кто-нибудь может дать теоретически обоснованную модель такому поведению, чтобы понять куда еще стоит посмотреть?
  6. XMega, EEPROM, NVM

    Аналогичное поведение в IAR. В IDLE продолжает писать. В power save\down с памяти снимается тактовая, так что не должен писать, остальные не пробовал.
  7. XMega, EEPROM, NVM

    В IAR в отладке тоже что-то подобное наблюдал с нулевой ячейкой. Не могли бы Вы сказать где проблема описана, есть желание почитать об этом.
  8. XMega, EEPROM, NVM

    Вы бы еще ревизию чипа читали перед использованием eeprom. В xmega128a1 до ревизии чипа H, был неприятный баг. У меня проявлялся следующим образом (тоже использовал map ram), при записи в eeprom контроллер прыгал на произвольный адрес flash. Нормально запустить получилось, только когда применил workaround из errata. Запись в eeprom - впадение ядра в idle - просыпание по прерыванию об окончании записи в eeprom. Первые партии xmega разных серий страдали этой бажиной, потом они ее пофиксили. Здесь как повезет. Мне два таких попалось, потом нормальные стали приходить. Немного о причинах введения NVM контроллера. На мой взгляд одна из причин это организация постраничного доступа. В AVR постраничный доступ был доступен только через программатор. Мне в софте приходится сливать в eeprom большие массивы данных, в xmega это не в пример быстрее происходит из-за постраничной организации.
  9. Есть некоторые начинания, но все они обламываются о лицензионный соглашения в зигби альянсе и в итоге глохнут. Насколько можно судить по ссылке все заглохло в 2009, а зигбишные спеки уже далеко вперед ушли. Если полазить по просторам интернета, то найдете попытки прикрутить зигби и в линукс. Но в итоге и там из-за проблем с лицензиями от альянса было решено использовать third part стеки.
  10. Собственно говоря открытых ZigBee стеков я думаю Вы не найдете.
  11. Метод проб и ошибок конечно тоже вариант, но вот я к стати вроде как нашел теоретическое подтверждение такому поведению. Книжка называется "The definitive guide to the arm cortex-M3" second edition by Joseph Yiu На 234 странице приведено "The rules of waking the Cortex-M3 processor from sleep modes" Table 14.2 WFI and WFE Wakeup Behavior WFI Behavior Wake Up IRQ Execution IRQ with BASEPRI IRQ priority > BASEPRIv Y Y IRQ priority =< BASEPRI N N IRQ with BASEPRI and PRIMASK IRQ priority > BASEPRI Y N IRQ priority =< BASEPRI N N WFE Behavior IRQ with BASEPRI, SEVONPEND = 0 IRQ priority > BASEPRI Y Y IRQ priority =< BASEPRI N N IRQ with BASEPRI, SEVONPEND = 1 IRQ priority > BASEPRI Y Y IRQ priority =< BASEPRI Y N IRQ with BASEPRI and PRIMASK, SEVONPEND = 0 IRQ priority > BASEPRI N N IRQ priority =< BASEPRI N N IRQ with BASEPRI & PRIMASK, SEVONPEND = 1 IRQ priority > BASEPRI Y N IRQ priority =< BASEPRI Y N То есть запрещая прерывание через cpsid i, мы устанавливаем PRIMASK, то есть попадаем в вариант 3, когда все прерывания приоритета выше чем BASEPRI будут будить ядро ноне будут инициировать прыжка на вектор. Но это только если уснуть через WFI. При засыпании через WFE эффекта не будет никакого, только если предварительно event не сгенерируется. Спасибо за то что идею подсказали, а то бы я долго лопатил все эти доки пока не наткнулся бы на эту таблицу.
  12. Что-то я не совсем понимаю. Мы запрещая прерывания, запрещаем контроллеру прыгать на их обработчики, но при это даже в запрещенном сотоянии это прерывание способно пробудить микроконтроллер?
  13. Всем здравствуйте )) Столкнулся с проблемой. Курил доки на mcu, искал в инете, но ответа на свой вопрос не смог найти. Суть собственно вот в чем: Есть желание во время простоя микроконтроллера переводить его в sleep mode, что собственно получается успешно делать. Также на плате есть чип, который может сгенерировать внешнее для mcu прерывание в любой момент времени. То есть оно может случиться например в момент выполнения процедуры ухода в сон. void IdleMode(void) { SCB->SCR &= ~SCR_SLEEPDEEP; // например прерывание происходит вот здесь PMC->PMC_FSMR &= ~PMC_FSMR_LPM; __WFE(); } Попав в прерывание я установлю флажок на его обработку в основном цикле и благополучно усну, при этом в основной обработчик могу попасть совсем не скоро, только когда еще одно прерывание произойдет. Например я знаю как такая ситуация обходится в avr. Там разрешают прерывания sei перед инструкцией sleep, а согласно доке на ядро, следующая инструкция после sei выполнится гарантированно. Есть ли здесь подобные механизмы? Кто-нибудь сталкивался такой проблемой и как обходил её?
  14. Полностью со всем согласен, и именно почти такие же аргументы и я приводил. Если бы за мной было бы последнее слово, никогда бы такую хрень дальше идеи не пропустил бы. Но к сожалению некоторые люди здравому смыслу не внемлют. Но это уже тема для других форумов, с медицинской тематикой :laughing: .
  15. Так камни с ядром avr имеют гарвардскую архитектуру и умеют исполнять код только из FLASH области, к сожалению это не cortex :crying: .