RSS
people

Операция прошла успешно

Ну что-ж,  пересадка головы прошла успешно.

И вот сегодня закончил перепись основных драйверов с STM32F429-го на STM32F746-й.

Вроде как все работает, хотя некоторые части еще не опробовал, но уже можно рассказать о небольших граблях, которые могут возникнуть при вот таком вот «перескоке» с одного проца на другой, причем с ARM Cortex M4 на ARM Cortex M7.

Итак...

1. FMS: (SDRAM, SRAM) — Unaligned Access. На 429-м при настройке FMC все начинало нормально работать. в 746-м, сразу после настройки FMC, возможен только доступ по четным (выровненным на 4 байта адресам). Для доступа к нечетным адресам надо еще настраивать MPU на эти области адресов. Иначе проц выпадает в Hard Fault exception handler.

  1. MPU_Region_InitTypeDef MPU_InitStruct_SDRAM;
  2.  MPU_Region_InitTypeDef MPU_InitStruct_FPGAKBD;
  3.  
  4.  /* Disable the MPU */
  5.  HAL_MPU_Disable();
  6.  
  7.  /* Configure the MPU attributes as WT for SDRAM */
  8.  MPU_InitStruct_SDRAM.Number = MPU_REGION_NUMBER0;
  9.  MPU_InitStruct_SDRAM.BaseAddress = 0xD0000000;
  10.  MPU_InitStruct_SDRAM.Size = MPU_REGION_SIZE_8MB;
  11.  
  12.  MPU_InitStruct_SDRAM.Enable = MPU_REGION_ENABLE;
  13.  MPU_InitStruct_SDRAM.AccessPermission = MPU_REGION_FULL_ACCESS;
  14.  MPU_InitStruct_SDRAM.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE;
  15.  MPU_InitStruct_SDRAM.IsCacheable = MPU_ACCESS_CACHEABLE;
  16.  MPU_InitStruct_SDRAM.IsShareable = MPU_ACCESS_NOT_SHAREABLE;
  17.  MPU_InitStruct_SDRAM.TypeExtField = MPU_TEX_LEVEL0;
  18.  MPU_InitStruct_SDRAM.SubRegionDisable = 0x00;
  19.  MPU_InitStruct_SDRAM.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE;
  20.  
  21.  HAL_MPU_ConfigRegion(&MPU_InitStruct_SDRAM);
  22.  
  23.  MPU_InitStruct_FPGAKBD.Number = MPU_REGION_NUMBER1;
  24.  MPU_InitStruct_FPGAKBD.BaseAddress = 0x60000000;
  25.  MPU_InitStruct_FPGAKBD.Size = MPU_REGION_SIZE_512MB;
  26.  
  27.  MPU_InitStruct_FPGAKBD.Enable = MPU_REGION_ENABLE;
  28.  MPU_InitStruct_FPGAKBD.AccessPermission = MPU_REGION_FULL_ACCESS;
  29.  MPU_InitStruct_FPGAKBD.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE;
  30.  MPU_InitStruct_FPGAKBD.IsCacheable = MPU_ACCESS_CACHEABLE;
  31.  MPU_InitStruct_FPGAKBD.IsShareable = MPU_ACCESS_NOT_SHAREABLE;
  32.  MPU_InitStruct_FPGAKBD.TypeExtField = MPU_TEX_LEVEL0;
  33.  MPU_InitStruct_FPGAKBD.SubRegionDisable = 0x00;
  34.  MPU_InitStruct_FPGAKBD.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE;
  35.  
  36.  HAL_MPU_ConfigRegion(&MPU_InitStruct_FPGAKBD);
  37.  /* Enable the MPU */
  38.  HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);

2. SPI: По началу — вроде все шло хорошо :) Но потом выяснилось, что тот код, который нормально работал на 429-м работает с некоторой странностью на 746-м — а именно, на каждый байт данных шлется целых 2!

Оказывается — нужно хитро оформлять доступ к регистру DR для того, чтобы послать один байт, так как сам регистр 16-ти битный, и при обычной записи в него — шлется два байта:

  1. if( len > 1 )
  2.  {
  3.    m_ctrl.peripf->DR = data;
  4.  }
  5.  else
  6.  {
  7.    *(volatile u08 *)&m_ctrl.peripf->DR = data;
  8.  }

  1. if(totalToTransfer > 1)
  2. {
  3.   data = m_ctrl.peripf->DR;
  4.   totalToTransfer -= 2;
  5.   if(totalToTransfer <= 1)
  6.   {
  7.     /* set fiforxthreshold before to switch on 8 bit data size */
  8.     SET_BIT(m_ctrl.peripf->CR2, SPI_RXFIFO_THRESHOLD);
  9.   }
  10. }
  11. else
  12. {
  13.   data = *(volatile u08 *)&m_ctrl.peripf->DR;
  14.   len = 1;
  15.   totalToTransfer--;
  16. }

Этот момент я подглядел в 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 всегда настроен, то я малость расширил функцию хэндлера, чтоб можно было получить всю интересную информацию в удобном виде.

Вот так примерно оно выглядит:

  1. #define USART_FLAG_TC ((uint16_t)0x0040)
  2. static __INLINE void ITM_SendChar_My (uint32_t ch)
  3. {
  4.  while( (USART1->ISR & USART_FLAG_TC ) == 0 )
  5.  {
  6.  ;
  7.  }
  8.  
  9.  USART1->TDR = (ch & (uint16_t)0x01FF);
  10. }
  11.  
  12. void printErrorMsg(const char * errMsg)
  13. {
  14.  while( *errMsg != 0 )
  15.  {
  16.  ITM_SendChar_My(*errMsg);
  17.  ++errMsg;
  18.  }
  19. }
  20.  
  21. void printUsageErrorMsg( uint32_t CFSRValue )
  22. {
  23.  printErrorMsg( "Usage fault: " );
  24.  CFSRValue >>= 16; // right shift to lsb
  25.  if( ( CFSRValue & ( 1 << 9 ) ) != 0 )
  26.  {
  27.  printErrorMsg( "Divide by zero\n" );
  28.  }
  29.  if( ( CFSRValue & ( 1 << 8 ) ) != 0 )
  30.  {
  31.  printErrorMsg( "Unaligned acc\n" );
  32.  }
  33.  if( ( CFSRValue & ( 1 << 3 ) ) != 0 )
  34.  {
  35.  printErrorMsg( "NO CP\n" );
  36.  }
  37.  if( ( CFSRValue & ( 1 << 2 ) ) != 0 )
  38.  {
  39.  printErrorMsg( "INV PC\n" );
  40.  }
  41.  if( ( CFSRValue & ( 1 << 1 ) ) != 0 )
  42.  {
  43.  printErrorMsg( "INV STATE\n" );
  44.  }
  45.  if( ( CFSRValue & ( 1 << 0) ) != 0 )
  46.  {
  47.  printErrorMsg( "UNDEF Instr\n" );
  48.  }
  49. }
  50. static char msg[80];
  51.  
  52. void printBusMemErrorMsg( uint32_t CFSRValue, uint32_t regVal )
  53. {
  54.  if( ( CFSRValue & ( 1 << 7 ) ) != 0 )
  55.  {
  56.  sprintf(msg, "Addr Reg valid: 0x%08x\n", (unsigned int)regVal);
  57.  printErrorMsg( msg );
  58.  }
  59.  if( ( CFSRValue & ( 1 << 5 ) ) != 0 )
  60.  {
  61.  printErrorMsg( "Float Point Lazy State Preserv\n" );
  62.  }
  63.  if( ( CFSRValue & ( 1 << 4 ) ) != 0 )
  64.  {
  65.  printErrorMsg( "Stacking Fault\n" );
  66.  }
  67.  if( ( CFSRValue & ( 1 << 3 ) ) != 0 )
  68.  {
  69.  printErrorMsg( "UNStacking Fault\n" );
  70.  }
  71.  if( ( CFSRValue & ( 1 << 1 ) ) != 0 )
  72.  {
  73.  printErrorMsg( "Data Acc viol\n" );
  74.  }
  75.  if( ( CFSRValue & ( 1 << 0) ) != 0 )
  76.  {
  77.  printErrorMsg( "Instr Acc viol\n" );
  78.  }
  79. }
  80.  
  81. void prvGetRegistersFromStack( uint32_t * pulFaultStackAddress, u32 faultSrc )
  82. {
  83.  /* These are volatile to try and prevent the compiler/linker optimising them
  84.  away as the variables never actually get used. If the debugger won't show the
  85.  values of the variables, make them global my moving their declaration outside
  86.  of this function. */
  87.  volatile uint32_t r0 __attribute__((unused));
  88.  volatile uint32_t r1 __attribute__((unused));
  89.  volatile uint32_t r2 __attribute__((unused));
  90.  volatile uint32_t r3 __attribute__((unused));
  91.  volatile uint32_t r12 __attribute__((unused));
  92.  volatile uint32_t lr __attribute__((unused)); /* Link register. */
  93.  volatile uint32_t pc __attribute__((unused)); /* Program counter. */
  94.  volatile uint32_t psr __attribute__((unused));/* Program status register. */
  95.  volatile uint32_t psp __attribute__((unused));
  96.  volatile uint32_t msp __attribute__((unused));
  97.  volatile uint32_t _CFSR __attribute__((unused));
  98.  volatile uint32_t _HFSR __attribute__((unused));
  99.  volatile uint32_t _DFSR __attribute__((unused));
  100.  volatile uint32_t _AFSR __attribute__((unused));
  101.  volatile uint32_t _BFAR __attribute__((unused));
  102.  volatile uint32_t _MMAR __attribute__((unused));
  103.  
  104.  r0 = pulFaultStackAddress[ 0 ];
  105.  r1 = pulFaultStackAddress[ 1 ];
  106.  r2 = pulFaultStackAddress[ 2 ];
  107.  r3 = pulFaultStackAddress[ 3 ];
  108.  
  109.  r12 = pulFaultStackAddress[ 4 ];
  110.  lr = pulFaultStackAddress[ 5 ];
  111.  pc = pulFaultStackAddress[ 6 ];
  112.  psr = pulFaultStackAddress[ 7 ];
  113.  
  114.  msp = __get_MSP();
  115.  psp = __get_PSP();
  116.  
  117.  // Configurable Fault Status Register
  118.  // Consists of MMSR, BFSR and UFSR
  119.  _CFSR = (*((volatile unsigned long *)(0xE000ED28))) ;
  120.  
  121.  // Hard Fault Status Register
  122.  _HFSR = (*((volatile unsigned long *)(0xE000ED2C))) ;
  123.  
  124.  // Debug Fault Status Register
  125.  _DFSR = (*((volatile unsigned long *)(0xE000ED30))) ;
  126.  
  127.  // Auxiliary Fault Status Register
  128.  _AFSR = (*((volatile unsigned long *)(0xE000ED3C))) ;
  129.  
  130.  // Read the Fault Address Registers. These may not contain valid values.
  131.  // Check BFARVALID/MMARVALID to see if they are valid values
  132.  // MemManage Fault Address Register
  133.  _MMAR = (*((volatile unsigned long *)(0xE000ED34))) ;
  134.  // Bus Fault Address Register
  135.  _BFAR = (*((volatile unsigned long *)(0xE000ED38))) ;
  136.  
  137.  USART1->CR1 &= ~(0x1F0); // Disable Interrupts
  138.  
  139.  if( faultSrc == 1 )
  140.  {
  141.  printErrorMsg("\nIn Hard Fault Handler\n");
  142.  }
  143.  else if( faultSrc == 2 )
  144.  {
  145.  printErrorMsg("\nIn Memory Managament Fault Handler\n");
  146.  }
  147.  else
  148.  {
  149.  printErrorMsg("\nIn Unknown Fault Handler\n");
  150.  }
  151.  
  152.  sprintf(msg, "MSP = 0x%08x\n", (unsigned int)msp); printErrorMsg(msg);
  153.  sprintf(msg, "PSP = 0x%08x\n", (unsigned int)psp); printErrorMsg(msg);
  154.  
  155.  sprintf(msg, "SCB->CFSR = 0x%08x\n", (unsigned int)_CFSR); printErrorMsg( msg );
  156.  sprintf(msg, "SCB->DFSR = 0x%08x\n", (unsigned int)_DFSR); printErrorMsg(msg);
  157.  sprintf(msg, "SCB->AFSR = 0x%08x\n", (unsigned int)_AFSR); printErrorMsg(msg);
  158.  sprintf(msg, "SCB->MMAR = 0x%08x\n", (unsigned int)_MMAR); printErrorMsg(msg);
  159.  sprintf(msg, "SCB->BFAR = 0x%08x\n", (unsigned int)_BFAR); printErrorMsg(msg);
  160.  sprintf(msg, "SCB->HFSR = 0x%08x\n", (unsigned int)_HFSR); printErrorMsg(msg);
  161.  
  162.  if ( ( SCB->HFSR & ( 1 << 30 ) ) != 0 )
  163.  {
  164.  printErrorMsg( "Forced Hard Fault\n" );
  165.  }
  166.  
  167.  if( ( _CFSR & 0xFFFF0000 ) != 0 )
  168.  {
  169.  printErrorMsg( "Hard Fault:\n" );
  170.  printUsageErrorMsg( _CFSR );
  171.  }
  172.  
  173.  if( ( _CFSR & 0x0000FFFF ) != 0 )
  174.  {
  175.  if( ( _CFSR & 0x000000FF ) != 0 )
  176.  {
  177.  printErrorMsg("Mem Mgmt Fault:\n");
  178.  printBusMemErrorMsg( _CFSR, _MMAR );
  179.  }
  180.  else
  181.  {
  182.  printErrorMsg("Bus Fault:\n");
  183.  printBusMemErrorMsg( _CFSR >> 8, _BFAR );
  184.  }
  185.  }
  186.  
  187.  sprintf(msg, "\nr0 = 0x%08x\n", (unsigned int)pulFaultStackAddress[0]); printErrorMsg(msg);
  188.  sprintf(msg, "r1 = 0x%08x\n", (unsigned int)pulFaultStackAddress[1]); printErrorMsg(msg);
  189.  sprintf(msg, "r2 = 0x%08x\n", (unsigned int)pulFaultStackAddress[2]); printErrorMsg(msg);
  190.  sprintf(msg, "r3 = 0x%08x\n", (unsigned int)pulFaultStackAddress[3]); printErrorMsg(msg);
  191.  sprintf(msg, "r12 = 0x%08x\n", (unsigned int)pulFaultStackAddress[4]); printErrorMsg(msg);
  192.  sprintf(msg, "lr = 0x%08x\n", (unsigned int)pulFaultStackAddress[5]); printErrorMsg(msg);
  193.  sprintf(msg, "pc = 0x%08x\n", (unsigned int)pulFaultStackAddress[6]); printErrorMsg(msg);
  194.  sprintf(msg, "psr = 0x%08x\n", (unsigned int)pulFaultStackAddress[7]); printErrorMsg(msg);
  195.  
  196.  __asm("BKPT #0\n") ; // Break into the debugger
  197.  
  198.  /* When the following line is hit, the variables contain the register values. */
  199.  volatile int a = 1;
  200.  while ( a ) ;
  201. }
  202. // -mfpu=fpv4-sp-d16
  203.  
  204. void HardFault_Handler( void ) //__attribute__ (( naked ))
  205. {
  206.  __asm volatile
  207.  (
  208.  " tst lr, #4 \n"
  209.  " ite eq \n"
  210.  " mrseq r0, msp \n"
  211.  " mrsne r0, psp \n"
  212.  " ldr r1, [r0, #24] \n"
  213.  " mov r1, 1 \n" /* Fault source */
  214.  " ldr r3, handler1_address_const \n"
  215.  " bx r3 \n"
  216.  " handler1_address_const: .word prvGetRegistersFromStack \n"
  217.  );
  218.  
  219.  while ( 1 )
  220.  {
  221.  ;
  222.  }
  223. }
  224.  
  225. void MemManage_Handler( void )
  226. {
  227.  __asm volatile
  228.  (
  229.  " tst lr, #4 \n"
  230.  " ite eq \n"
  231.  " mrseq r0, msp \n"
  232.  " mrsne r0, psp \n"
  233.  " ldr r1, [r0, #24] \n"
  234.  " mov r1, 2 \n" /* Fault source */
  235.  " ldr r3, handler2_address_const \n"
  236.  " bx r3 \n"
  237.  " handler2_address_const: .word prvGetRegistersFromStack \n"
  238.  );
  239.  while ( 1 )
  240.  {
  241.  __asm("BKPT #0\n") ; // Break into the debugger
  242.  ;
  243.  }
  244. }

 

PS: Кстати, по ощущениям — проц работает быстрее раза в три-четыре, по сравнению со старым.

2 комментария к “Операция прошла успешно”

  1. Kitano8 пишет:

    Воо. Пишите еще. Интересные статьи. И не пропадайте

  2. MasterAlexei пишет:

    Так время оно такое — оно вроде бы есть, и его вроде бы и нет. :)

Оставить комментарий или два

Пожалуйста, зарегистрируйтесь для комментирования.