Individální projekty MPOA

Mikroprocesory s architekturou ARM

Uživatelské nástroje

Nástroje pro tento web


2015:rot-control

Toto je starší verze dokumentu!


Not final

Modul pro řízení mechanického rotačního systému

  • David Krolák
  • xkrola00@stud.feec.vutbr.cz

Zadání

Prostřednictvím vývojové desky vhodně zvoleného mikrokontroléru s architekturou ARM realizujte řízení mechanického rotačního systému, skládajícího se z DC motorku a inkrementálního enkodéru. Implementujte funkce otáčení zvolenou rychlostí, natočení o požadovaný úhel a ukládání aktuální pozice v závislosti na synchronizačním signálu.

Úvod

Uvedený projekt je součástí diplomové práce na téma Modul pro verifikaci rotačních pozičních senzorů, jejímž výstupem je návrh řídícího modulu včetně komunikačního rozhraní pro rotační systém dostupný na pracovišti firmy ON Design Czech. Cílem tohoto projektu je vytvořit program pro vhodně zvolenou vývojovou desku mikrokontroléru (dále MCU kit) umožňující jak řízení systému tak i časově synchronizovaný záznam velkého množství aktuálních pozic.

Použitý hardware a popis funkce

Mechanický rotační systém se skládá ze stejnosměrného motorku vybaveného planetovou převodovkou s převodem do pomala. Dále z inkrementálního kvadraturního rotačního kodéru a lineárního čtyřkvadrantového servozesilovače, který udržuje nastavené otáčky konstantní díky zpětné vazbě z tachodynama. Systém je uveden na následující fotografii. Rotační systém

Primární aplikací modulu je testování při vývoji bezkontaktních indukčních pozičních senzorů, kdy se vyhodnocuje přesnost měřeného úhlu natočení vůči referenční hodnotě zaznamenané právě touto jednotkou. Aplikační zapojení si lze prohlédnout na následujícím obrázku, kde A, B tvoří kvadraturní signál kodéru (vzájemný fázový posuv 90°) a M je tzv. index signál informující svou nástupnou hranou o počáteční pozici rotoru. Řídící signály STEP a DIR slouží k řízení otočení o předem definovaný krok. REQB je synchronizační singál jehož sestupná hrana definuje časové okamžiky zápisu aktuální pozice rotoru. Otáčky motorku se řídí velikosti napětí signálu SPD na vstupu lineárního zesilovače, kdy kladné napětí znamená otáčení ve směru hodinových ručiček a záporné napětí směr opačný. Digitální signál STOP nastavuje nulový točivý moment, aby se rotor neotáčel díky napěťovému ofsetu. Aplikace modulu

Volba MCU závisí na požadavcích aplikace modulu, mezi které patří dostatečná kapacita datové paměti, schopnost komunikovat s počítačem v dnešní době především přes USB, vysoký taktovací kmitočet pro dostatečně rychlou reakci na synchronizační signál, hardwarová podpora pro inkrementální kodér a digitálně analogový převodník (DAC) s vyhovujícím rozlišením. Těmto požadavkům vyhovuje vývojový kit STM32F429 Discovery od výrobce STMicroelectronics osazený 32 bitovým MCU STM32F429ZI s jádrem Cortex-M4 architektury ARM. Tento kit disponuje mimo jiné datovou pamětí SDRAM s kapacitou 8 MB.

Vybrané parametry STM32F429ZI:

  • 2 MB Flash paměť programu
  • 256 + 4 KB SRAM datovou paměť obsahující 64 KB CCM (Core Coupled Memory)
  • FMC (flexibilní kontrolér externí paměti) podporující až 32 bitovou datovou sběrnici
  • 2x 12 bitový DAC
  • Ze 17 časovačů dva 32 bitové a dva 16 bitové s možností funkce jako čítač pro kvadraturní inkrementální kodér
  • Maximální interní taktovací kmitočet 180 MHZ získaný PLL násobičkou z externího krystalu 4 až 26 MHz
  • pokročilou konektivitu USB 2.0 HS/FS (High-speed/Full-speed) device/host/OTG (On-the-Go) s full-speed PHY na čipu

Blokové zapojení řídící jednotky se zvoleným vývojovým kitem si lze prohlédnout na obrázku: Koncept modulu

Další obrázek ukazuje volbu vstupně/výstupních vývodů pro řídící signály a rotační kodér včetně analogového výstupu z převodníku. Propojení s kitem

Firmware

Stavový diagram

static int8_t CDC_Control_HS  (uint8_t cmd, uint8_t* pbuf, uint16_t length)
{
  /* USER CODE BEGIN 10 */
  switch (cmd)
  {
    ...   
    case CDC_SET_LINE_CODING:
    /* Add your code here */
    tempbuf[0] = pbuf[0];
    tempbuf[1] = pbuf[1];
    tempbuf[2] = pbuf[2];
    tempbuf[3] = pbuf[3];
    tempbuf[4] = pbuf[4];
    tempbuf[5] = pbuf[5];
    tempbuf[6] = pbuf[6];
    break;
 
  case CDC_GET_LINE_CODING:
    /* Add your code here */
    pbuf[0] = tempbuf[0];
    pbuf[1] = tempbuf[1];
    pbuf[2] = tempbuf[2];
    pbuf[3] = tempbuf[3];
    pbuf[4] = tempbuf[4];
    pbuf[5] = tempbuf[5];
    pbuf[6] = tempbuf[6];
    break;    
    ...
  }
 
  return (USBD_OK);
  /* USER CODE END 10 */
}  
static int8_t CDC_Receive_HS (uint8_t* Buf, uint32_t *Len)
{
  /* USER CODE BEGIN 11 */
  /* Loopback */
  CDC_Transmit_HS(Buf, *Len);
  USBD_CDC_ReceivePacket(hUsbDevice_1);
 
  /* Get data from the VCP in register */
  CDC_data_in[CDC_data_count] = UserRxBufferHS[0];
 
  if(CDC_data_in[CDC_data_count] == RETURN)
  {
      CDC_command_ready = TRUE;
      CDC_data_count = 0;
  }
  else
  {
      CDC_data_count++;
  }
 
  return (USBD_OK);
  /* USER CODE END 11 */
}
void CDC_Send_HS(char* Buf, uint16_t Len)
{
    static uint8_t sent    = 0;
    static uint8_t try_cnt = 0;
 
    while(!sent)
    {
        /* Check if is possible send data ten times maximally */
        if(((USBD_CDC_HandleTypeDef*)(hUsbDeviceHS.pClassData))->TxState == 0)
        {
            /* Data send with value check */
            if(CDC_Transmit_HS((uint8_t*)(Buf), Len) == USBD_OK)
            {
                sent = 1;
            }
        }
        else if(try_cnt > 9)
        {
            sent = 1;
        }
 
        try_cnt++;
        if(sent == 0)
        {
            HAL_Delay(1);
        }
    }
}
void MX_TIM8_Init(void)
{
  TIM_Encoder_InitTypeDef sConfig;
  TIM_MasterConfigTypeDef sMasterConfig;
 
  htim8.Instance               = TIM8;
  htim8.Init.Prescaler         = 0;
  htim8.Init.CounterMode       = TIM_COUNTERMODE_UP;
  htim8.Init.Period            = Encoder_rep_res;
  htim8.Init.ClockDivision     = TIM_CLOCKDIVISION_DIV1;
  htim8.Init.RepetitionCounter = 0;
 
  sConfig.EncoderMode  = TIM_ENCODERMODE_TI12;
  sConfig.IC1Polarity  = TIM_ICPOLARITY_RISING;
  sConfig.IC1Selection = TIM_ICSELECTION_DIRECTTI;
  sConfig.IC1Prescaler = TIM_ICPSC_DIV1;
  sConfig.IC1Filter    = 0;
  sConfig.IC2Polarity  = TIM_ICPOLARITY_RISING;
  sConfig.IC2Selection = TIM_ICSELECTION_DIRECTTI;
  sConfig.IC2Prescaler = TIM_ICPSC_DIV1;
  sConfig.IC2Filter    = 0;
 
  HAL_TIM_Encoder_Init(&htim8, &sConfig);
 
  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  HAL_TIMEx_MasterConfigSynchronization(&htim8, &sMasterConfig);
 
  /* Enable update interrupt */
  __HAL_TIM_CLEAR_FLAG(&htim8, TIM_SR_UIF);
  __HAL_TIM_ENABLE_IT(&htim8, TIM_DIER_UIE);
}
void MX_FMC_Init(void)
{
  FMC_SDRAM_TimingTypeDef  SdramTiming;
  FMC_SDRAM_CommandTypeDef Command;
 
  /** Perform the SDRAM1 memory initialization sequence
  */
  hsdram1.Instance                = FMC_SDRAM_DEVICE;
 
  /* hsdram1.Init */
  hsdram1.Init.SDBank             = FMC_SDRAM_BANK2;
  hsdram1.Init.ColumnBitsNumber   = FMC_SDRAM_COLUMN_BITS_NUM_8;
  hsdram1.Init.RowBitsNumber      = FMC_SDRAM_ROW_BITS_NUM_12;
  hsdram1.Init.MemoryDataWidth    = FMC_SDRAM_MEM_BUS_WIDTH_16;
  hsdram1.Init.InternalBankNumber = FMC_SDRAM_INTERN_BANKS_NUM_4;
  hsdram1.Init.CASLatency         = FMC_SDRAM_CAS_LATENCY_3;
  hsdram1.Init.WriteProtection    = FMC_SDRAM_WRITE_PROTECTION_DISABLE;
  hsdram1.Init.SDClockPeriod      = FMC_SDRAM_CLOCK_PERIOD_2;
  hsdram1.Init.ReadBurst          = FMC_SDRAM_RBURST_DISABLE;
  hsdram1.Init.ReadPipeDelay      = FMC_SDRAM_RPIPE_DELAY_1;
 
  /* SDRAM Timing configuration for 84 MHz (11.9 ns) of SD clock frequency (168MHz/2) */
  /* TMRD: 2 clock cycles */
  SdramTiming.LoadToActiveDelay    = 2;
  /* TXSR: min = 70 ns (7 times 11.9 ns) */
  SdramTiming.ExitSelfRefreshDelay = 7;
  /* TRAS: min = 42 ns (4 times 11.9 ns) */
  SdramTiming.SelfRefreshTime      = 4;
  /* TRC:  min = 63 ns (7 times 11.9 ns) */
  SdramTiming.RowCycleDelay        = 7;
  /* TWR:  2 Clock cycles */
  SdramTiming.WriteRecoveryTime    = 2;
  /* TRP:  15 ns => 2 times 11.9 ns */
  SdramTiming.RPDelay              = 2;
  /* TRCD: 15 ns => 2 times 11.9 ns */
  SdramTiming.RCDDelay             = 2;
 
  HAL_SDRAM_Init(&hsdram1, &SdramTiming);
 
  /* Send commands to the SDRAM */
  /* 1/ SDRAM clock enable command */
  Command.CommandMode            = FMC_SDRAM_CMD_CLK_ENABLE;
  Command.CommandTarget          = FMC_SDRAM_CMD_TARGET_BANK2;
  Command.AutoRefreshNumber      = 1;
  Command.ModeRegisterDefinition = 0;
 
  HAL_SDRAM_SendCommand(&hsdram1, &Command, SDRAM_TIMEOUT);
 
  /* 2/ Insert 100 ms delay */
  HAL_Delay(100);
 
  /* 3/ Configure a PALL (precharge all) command */
  Command.CommandMode            = FMC_SDRAM_CMD_PALL;
  Command.CommandTarget          = FMC_SDRAM_CMD_TARGET_BANK2;
  Command.AutoRefreshNumber      = 1;
  Command.ModeRegisterDefinition = 0;
 
  HAL_SDRAM_SendCommand(&hsdram1, &Command, SDRAM_TIMEOUT);
 
  /* 4/ Configure a Auto-Refresh command */
  Command.CommandMode            = FMC_SDRAM_CMD_AUTOREFRESH_MODE;
  Command.CommandTarget          = FMC_SDRAM_CMD_TARGET_BANK2;
  Command.AutoRefreshNumber      = 8;
  Command.ModeRegisterDefinition = 0;
 
  HAL_SDRAM_SendCommand(&hsdram1, &Command, SDRAM_TIMEOUT);
 
  /* 5/ Program the external memory mode register */
  Command.CommandMode            = FMC_SDRAM_CMD_LOAD_MODE;
  Command.CommandTarget          = FMC_SDRAM_CMD_TARGET_BANK2;
  Command.AutoRefreshNumber      = 1;
  Command.ModeRegisterDefinition = (uint32_t)SDRAM_REG_VALUE;
 
  HAL_SDRAM_SendCommand(&hsdram1, &Command, SDRAM_TIMEOUT);
 
  /* 6/ Set the refresh rate counter */
  HAL_SDRAM_ProgramRefreshRate(&hsdram1, REFRESH_COUNT);
  HAL_Delay(100);
}

Test SDRAM 8 MB

static void Encoder_Emulator_Init(TIM_HandleTypeDef* htim)
{
  /* Initialize TIM1 peripheral */
  htim->Instance           = TIM1;
  htim->Init.Period        = EMU_PERIOD;
  htim->Init.Prescaler     = PSC;
  htim->Init.ClockDivision = 0;
  htim->Init.CounterMode   = TIM_COUNTERMODE_UP;
 
  HAL_TIM_OC_Init(htim);
 
  /* Configure the output compare channels */
  /* Output compare toggle mode configuration: Channel1 */
  sConfigEmulator.OCMode     = TIM_OCMODE_TOGGLE;
  sConfigEmulator.Pulse      = (EMU_PERIOD * 1)/4;
  sConfigEmulator.OCPolarity = TIM_OCPOLARITY_LOW;
 
  HAL_TIM_OC_ConfigChannel(htim, &sConfigEmulator, TIM_CHANNEL_2);
 
  /* Output compare toggle mode configuration: Channel2 */
  sConfigEmulator.Pulse      = (EMU_PERIOD * 3)/4;
  HAL_TIM_OC_ConfigChannel(htim, &sConfigEmulator, TIM_CHANNEL_3);
}

Ukázka činnosti

Text Test programu s emulovaným kodérem

Zdrojové soubory

Závěr

2015/rot-control.1453068117.txt.gz · Poslední úprava: 2016/01/17 23:01 autor: David Krolák