Ну что-ж, пересадка головы прошла успешно.
И вот сегодня закончил перепись основных драйверов с STM32F429-го на STM32F746-й.
Вроде как все работает, хотя некоторые части еще не опробовал, но уже можно рассказать о небольших граблях, которые могут возникнуть при вот таком вот «перескоке» с одного проца на другой, причем с ARM Cortex M4 на ARM Cortex M7.
Итак...
1. FMS: (SDRAM, SRAM) — Unaligned Access. На 429-м при настройке FMC все начинало нормально работать. в 746-м, сразу после настройки FMC, возможен только доступ по четным (выровненным на 4 байта адресам). Для доступа к нечетным адресам надо еще настраивать MPU на эти области адресов. Иначе проц выпадает в Hard Fault exception handler.
- MPU_Region_InitTypeDef MPU_InitStruct_SDRAM;
- MPU_Region_InitTypeDef MPU_InitStruct_FPGAKBD;
- /* Disable the MPU */
- HAL_MPU_Disable();
- /* Configure the MPU attributes as WT for SDRAM */
- MPU_InitStruct_SDRAM.Number = MPU_REGION_NUMBER0;
- MPU_InitStruct_SDRAM.BaseAddress = 0xD0000000;
- MPU_InitStruct_SDRAM.Size = MPU_REGION_SIZE_8MB;
- MPU_InitStruct_SDRAM.Enable = MPU_REGION_ENABLE;
- MPU_InitStruct_SDRAM.AccessPermission = MPU_REGION_FULL_ACCESS;
- MPU_InitStruct_SDRAM.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE;
- MPU_InitStruct_SDRAM.IsCacheable = MPU_ACCESS_CACHEABLE;
- MPU_InitStruct_SDRAM.IsShareable = MPU_ACCESS_NOT_SHAREABLE;
- MPU_InitStruct_SDRAM.TypeExtField = MPU_TEX_LEVEL0;
- MPU_InitStruct_SDRAM.SubRegionDisable = 0x00;
- MPU_InitStruct_SDRAM.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE;
- HAL_MPU_ConfigRegion(&MPU_InitStruct_SDRAM);
- MPU_InitStruct_FPGAKBD.Number = MPU_REGION_NUMBER1;
- MPU_InitStruct_FPGAKBD.BaseAddress = 0x60000000;
- MPU_InitStruct_FPGAKBD.Size = MPU_REGION_SIZE_512MB;
- MPU_InitStruct_FPGAKBD.Enable = MPU_REGION_ENABLE;
- MPU_InitStruct_FPGAKBD.AccessPermission = MPU_REGION_FULL_ACCESS;
- MPU_InitStruct_FPGAKBD.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE;
- MPU_InitStruct_FPGAKBD.IsCacheable = MPU_ACCESS_CACHEABLE;
- MPU_InitStruct_FPGAKBD.IsShareable = MPU_ACCESS_NOT_SHAREABLE;
- MPU_InitStruct_FPGAKBD.TypeExtField = MPU_TEX_LEVEL0;
- MPU_InitStruct_FPGAKBD.SubRegionDisable = 0x00;
- MPU_InitStruct_FPGAKBD.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE;
- HAL_MPU_ConfigRegion(&MPU_InitStruct_FPGAKBD);
- /* Enable the MPU */
- HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);
2. SPI: По началу — вроде все шло хорошо Но потом выяснилось, что тот код, который нормально работал на 429-м работает с некоторой странностью на 746-м — а именно, на каждый байт данных шлется целых 2!
Оказывается — нужно хитро оформлять доступ к регистру DR для того, чтобы послать один байт, так как сам регистр 16-ти битный, и при обычной записи в него — шлется два байта:
- if( len > 1 )
- {
- m_ctrl.peripf->DR = data;
- }
- else
- {
- *(volatile u08 *)&m_ctrl.peripf->DR = data;
- }
- if(totalToTransfer > 1)
- {
- data = m_ctrl.peripf->DR;
- totalToTransfer -= 2;
- if(totalToTransfer <= 1)
- {
- /* set fiforxthreshold before to switch on 8 bit data size */
- SET_BIT(m_ctrl.peripf->CR2, SPI_RXFIFO_THRESHOLD);
- }
- }
- else
- {
- data = *(volatile u08 *)&m_ctrl.peripf->DR;
- len = 1;
- totalToTransfer--;
- }
Этот момент я подглядел в HAL-е от ST. Комментарий тоже оттуда. Кстати, на прием настраиваем порог срабатывания прерывания сначала на половину буфера, т.е. на 16 бит, и потом, если остался только один байт на прием, переключаем этот порог на 8 бит.
Но я не использовал прерывания, а просто постоянно проверял флаги статусов. В общем — полллингом занимался. С прерываниями у меня как то не вышло...
3. DMA. У меня UART на DMA работает, и вроде как, во время отладки и пошагового прохождения программы все работало нормально, а когда все запускал в обычном режиме — в терминале стали пропадать отладочные сообщения прямо пачками.
Немного покумекав, вспомнил такую же проблему в одном из проектов по работе (там у нас ARM9 был). Оказалось — у ARM7 есть кеш данных и инструкций.
Таким образом, при работе c DMA, когда сразу после окончания транзакции DMA надо использовать данные — надо сначала «пошаманить» с кешем такими функциями:
При старте DMA:
SCB_CleanDCache_by_Addr ( (u32 *)(portDefines->dmaTxBuff), UART_TX_BUFF_LEN );
После работы DMA:
SCB_InvalidateDCache_by_Addr ( (u32 *)(&m_dmaRxBuff[ ...]), UART_DMA_RX_BUFF_MIDLE );
Ну вроде как пока все, что вспомнил. Еще не проверил, работает ли генерация PWM сигналов, хотя вроде как должно работать, как мне кажется.
Небольшой бонус:
При разработке на ARM-ах часто проц выпадает в Hard Fault Handler. И хочется узнать, а от чего он туда попадает.
На просторах интернета и в Programming Manual нашел, что при таких вот Fault'ах проц сохраняет некоторые регистры в стеке, и есть еще несколько полезных регистров.
Так как у меня UART всегда настроен, то я малость расширил функцию хэндлера, чтоб можно было получить всю интересную информацию в удобном виде.
Вот так примерно оно выглядит:
- #define USART_FLAG_TC ((uint16_t)0x0040)
- static __INLINE void ITM_SendChar_My (uint32_t ch)
- {
- while( (USART1->ISR & USART_FLAG_TC ) == 0 )
- {
- ;
- }
- USART1->TDR = (ch & (uint16_t)0x01FF);
- }
- void printErrorMsg(const char * errMsg)
- {
- while( *errMsg != 0 )
- {
- ITM_SendChar_My(*errMsg);
- ++errMsg;
- }
- }
- void printUsageErrorMsg( uint32_t CFSRValue )
- {
- printErrorMsg( "Usage fault: " );
- CFSRValue >>= 16; // right shift to lsb
- if( ( CFSRValue & ( 1 << 9 ) ) != 0 )
- {
- printErrorMsg( "Divide by zero\n" );
- }
- if( ( CFSRValue & ( 1 << 8 ) ) != 0 )
- {
- printErrorMsg( "Unaligned acc\n" );
- }
- if( ( CFSRValue & ( 1 << 3 ) ) != 0 )
- {
- printErrorMsg( "NO CP\n" );
- }
- if( ( CFSRValue & ( 1 << 2 ) ) != 0 )
- {
- printErrorMsg( "INV PC\n" );
- }
- if( ( CFSRValue & ( 1 << 1 ) ) != 0 )
- {
- printErrorMsg( "INV STATE\n" );
- }
- if( ( CFSRValue & ( 1 << 0) ) != 0 )
- {
- printErrorMsg( "UNDEF Instr\n" );
- }
- }
- static char msg[80];
- void printBusMemErrorMsg( uint32_t CFSRValue, uint32_t regVal )
- {
- if( ( CFSRValue & ( 1 << 7 ) ) != 0 )
- {
- sprintf(msg, "Addr Reg valid: 0x%08x\n", (unsigned int)regVal);
- printErrorMsg( msg );
- }
- if( ( CFSRValue & ( 1 << 5 ) ) != 0 )
- {
- printErrorMsg( "Float Point Lazy State Preserv\n" );
- }
- if( ( CFSRValue & ( 1 << 4 ) ) != 0 )
- {
- printErrorMsg( "Stacking Fault\n" );
- }
- if( ( CFSRValue & ( 1 << 3 ) ) != 0 )
- {
- printErrorMsg( "UNStacking Fault\n" );
- }
- if( ( CFSRValue & ( 1 << 1 ) ) != 0 )
- {
- printErrorMsg( "Data Acc viol\n" );
- }
- if( ( CFSRValue & ( 1 << 0) ) != 0 )
- {
- printErrorMsg( "Instr Acc viol\n" );
- }
- }
- void prvGetRegistersFromStack( uint32_t * pulFaultStackAddress, u32 faultSrc )
- {
- /* These are volatile to try and prevent the compiler/linker optimising them
- away as the variables never actually get used. If the debugger won't show the
- values of the variables, make them global my moving their declaration outside
- of this function. */
- volatile uint32_t r0 __attribute__((unused));
- volatile uint32_t r1 __attribute__((unused));
- volatile uint32_t r2 __attribute__((unused));
- volatile uint32_t r3 __attribute__((unused));
- volatile uint32_t r12 __attribute__((unused));
- volatile uint32_t lr __attribute__((unused)); /* Link register. */
- volatile uint32_t pc __attribute__((unused)); /* Program counter. */
- volatile uint32_t psr __attribute__((unused));/* Program status register. */
- volatile uint32_t psp __attribute__((unused));
- volatile uint32_t msp __attribute__((unused));
- volatile uint32_t _CFSR __attribute__((unused));
- volatile uint32_t _HFSR __attribute__((unused));
- volatile uint32_t _DFSR __attribute__((unused));
- volatile uint32_t _AFSR __attribute__((unused));
- volatile uint32_t _BFAR __attribute__((unused));
- volatile uint32_t _MMAR __attribute__((unused));
- r0 = pulFaultStackAddress[ 0 ];
- r1 = pulFaultStackAddress[ 1 ];
- r2 = pulFaultStackAddress[ 2 ];
- r3 = pulFaultStackAddress[ 3 ];
- r12 = pulFaultStackAddress[ 4 ];
- lr = pulFaultStackAddress[ 5 ];
- pc = pulFaultStackAddress[ 6 ];
- psr = pulFaultStackAddress[ 7 ];
- msp = __get_MSP();
- psp = __get_PSP();
- // Configurable Fault Status Register
- // Consists of MMSR, BFSR and UFSR
- _CFSR = (*((volatile unsigned long *)(0xE000ED28))) ;
- // Hard Fault Status Register
- _HFSR = (*((volatile unsigned long *)(0xE000ED2C))) ;
- // Debug Fault Status Register
- _DFSR = (*((volatile unsigned long *)(0xE000ED30))) ;
- // Auxiliary Fault Status Register
- _AFSR = (*((volatile unsigned long *)(0xE000ED3C))) ;
- // Read the Fault Address Registers. These may not contain valid values.
- // Check BFARVALID/MMARVALID to see if they are valid values
- // MemManage Fault Address Register
- _MMAR = (*((volatile unsigned long *)(0xE000ED34))) ;
- // Bus Fault Address Register
- _BFAR = (*((volatile unsigned long *)(0xE000ED38))) ;
- USART1->CR1 &= ~(0x1F0); // Disable Interrupts
- if( faultSrc == 1 )
- {
- printErrorMsg("\nIn Hard Fault Handler\n");
- }
- else if( faultSrc == 2 )
- {
- printErrorMsg("\nIn Memory Managament Fault Handler\n");
- }
- else
- {
- printErrorMsg("\nIn Unknown Fault Handler\n");
- }
- sprintf(msg, "MSP = 0x%08x\n", (unsigned int)msp); printErrorMsg(msg);
- sprintf(msg, "PSP = 0x%08x\n", (unsigned int)psp); printErrorMsg(msg);
- sprintf(msg, "SCB->CFSR = 0x%08x\n", (unsigned int)_CFSR); printErrorMsg( msg );
- sprintf(msg, "SCB->DFSR = 0x%08x\n", (unsigned int)_DFSR); printErrorMsg(msg);
- sprintf(msg, "SCB->AFSR = 0x%08x\n", (unsigned int)_AFSR); printErrorMsg(msg);
- sprintf(msg, "SCB->MMAR = 0x%08x\n", (unsigned int)_MMAR); printErrorMsg(msg);
- sprintf(msg, "SCB->BFAR = 0x%08x\n", (unsigned int)_BFAR); printErrorMsg(msg);
- sprintf(msg, "SCB->HFSR = 0x%08x\n", (unsigned int)_HFSR); printErrorMsg(msg);
- if ( ( SCB->HFSR & ( 1 << 30 ) ) != 0 )
- {
- printErrorMsg( "Forced Hard Fault\n" );
- }
- if( ( _CFSR & 0xFFFF0000 ) != 0 )
- {
- printErrorMsg( "Hard Fault:\n" );
- printUsageErrorMsg( _CFSR );
- }
- if( ( _CFSR & 0x0000FFFF ) != 0 )
- {
- if( ( _CFSR & 0x000000FF ) != 0 )
- {
- printErrorMsg("Mem Mgmt Fault:\n");
- printBusMemErrorMsg( _CFSR, _MMAR );
- }
- else
- {
- printErrorMsg("Bus Fault:\n");
- printBusMemErrorMsg( _CFSR >> 8, _BFAR );
- }
- }
- sprintf(msg, "\nr0 = 0x%08x\n", (unsigned int)pulFaultStackAddress[0]); printErrorMsg(msg);
- sprintf(msg, "r1 = 0x%08x\n", (unsigned int)pulFaultStackAddress[1]); printErrorMsg(msg);
- sprintf(msg, "r2 = 0x%08x\n", (unsigned int)pulFaultStackAddress[2]); printErrorMsg(msg);
- sprintf(msg, "r3 = 0x%08x\n", (unsigned int)pulFaultStackAddress[3]); printErrorMsg(msg);
- sprintf(msg, "r12 = 0x%08x\n", (unsigned int)pulFaultStackAddress[4]); printErrorMsg(msg);
- sprintf(msg, "lr = 0x%08x\n", (unsigned int)pulFaultStackAddress[5]); printErrorMsg(msg);
- sprintf(msg, "pc = 0x%08x\n", (unsigned int)pulFaultStackAddress[6]); printErrorMsg(msg);
- sprintf(msg, "psr = 0x%08x\n", (unsigned int)pulFaultStackAddress[7]); printErrorMsg(msg);
- __asm("BKPT #0\n") ; // Break into the debugger
- /* When the following line is hit, the variables contain the register values. */
- volatile int a = 1;
- while ( a ) ;
- }
- // -mfpu=fpv4-sp-d16
- void HardFault_Handler( void ) //__attribute__ (( naked ))
- {
- __asm volatile
- (
- " tst lr, #4 \n"
- " ite eq \n"
- " mrseq r0, msp \n"
- " mrsne r0, psp \n"
- " ldr r1, [r0, #24] \n"
- " mov r1, 1 \n" /* Fault source */
- " ldr r3, handler1_address_const \n"
- " bx r3 \n"
- " handler1_address_const: .word prvGetRegistersFromStack \n"
- );
- while ( 1 )
- {
- ;
- }
- }
- void MemManage_Handler( void )
- {
- __asm volatile
- (
- " tst lr, #4 \n"
- " ite eq \n"
- " mrseq r0, msp \n"
- " mrsne r0, psp \n"
- " ldr r1, [r0, #24] \n"
- " mov r1, 2 \n" /* Fault source */
- " ldr r3, handler2_address_const \n"
- " bx r3 \n"
- " handler2_address_const: .word prvGetRegistersFromStack \n"
- );
- while ( 1 )
- {
- __asm("BKPT #0\n") ; // Break into the debugger
- ;
- }
- }
PS: Кстати, по ощущениям — проц работает быстрее раза в три-четыре, по сравнению со старым.
2 комментария к “Операция прошла успешно”
Оставить комментарий или два
Пожалуйста, зарегистрируйтесь для комментирования.
28th April 2016 в 22:33
Воо. Пишите еще. Интересные статьи. И не пропадайте
28th April 2016 в 22:57
Так время оно такое — оно вроде бы есть, и его вроде бы и нет.