wtorek, 18 października 2016

[21] STM32F4 - Generacja liczb pseudolosowych

Ten post chciałbym poświecić na opisanie sprzętowego bloku pozwalającego na generowanie 32 bitowych liczb pseudolosowych.

Opis bloku [1]:


Ta część będzie poświęcona na opis bloku RNG. Generator liczb pseudolosowych, który jest oparty o część analogową, jest wykorzystywany w większości mikrokontrolerów z rodziny STM32F2, F4, F7, L0 oraz L4.

Jak już wspomniałem generator jest oparty o obwód analogowy, który generuje ciągły szum. Jest on wytwarzany do przygotowania 32 bitowych próbek. Część analogowa jest przygotowana z kilku oscylatorotów z wyjściamu XOR. Taktowanie odbywa się poprzez linię AHB1.

Programowanie:


W pierwszej kolejności należy włączyć sygnał zegarowy:

  1. RCC_AHB2PeriphClockCmd(RCC_AHB2Periph_RNG, ENABLE);
  2. //lub na rejestrach
  3. RCC->AHB2ENR |= RCC_AHB2ENR_RNGEN; //((uint32_t)0x00000040)
  4. __DSB();

Włączenie modułu odbywa się za pomocą funkcji RNG_Cmd(), która wygląda następująco:

  1. void RNG_Cmd(FunctionalState NewState)
  2. {
  3.   //Sprawdzenie parametrow
  4.   assert_param(IS_FUNCTIONAL_STATE(NewState));
  5.   if (NewState != DISABLE)
  6.   {
  7.     //Wlaczenie RNG
  8.     RNG->CR |= RNG_CR_RNGEN;
  9.   }
  10.   else
  11.   {
  12.     //Wylaczenie RNG
  13.     RNG->CR &= ~RNG_CR_RNGEN;
  14.   }
  15. }

Włączenie odbywa się poprzez wprowadzenie instrukcji RNG_Cmd(ENABLE) wyłączenie natomiast poprzez RNG_Cmd(DISABLE). Funkcja ustawia w rejestrze kontrolnym RNG bity odpowiedzialne za włączenie układu (dokładnie podaje wartość 0x00000004).

Pobranie wartości odbywa się przy użyciu funkcji RNG_GetRandomNumber();

  1. uint32_t RNG_GetRandomNumber(void)
  2. {
  3.   return RNG->DR;
  4. }

Zwraca ona 32 bitową wartość wyprowadzoną z rejestru DR.

Poniżej przedstawię krótki program który będzie wykonywał dwie operacje, jedną z nich będzie przesłanie danych poprzez UART do komputera, druga będzie miała za zadanie mruganie diodami wbudowanymi na płytkę discovery w zależności od otrzymanej wartości.

  1. #include "stm32f4xx.h"
  2. #include "stm32f4xx_rcc.h"
  3. #include "stm32f4xx_usart.h"
  4. #include "stdio.h"
  5. #include "misc.h"
  6. struct __FILE {
  7.     int parametr;
  8. };
  9. FILE __stdout;
  10. void send_char(char);
  11. void USART_Initialize(void);
  12. void GPIO_Initialize(void);
  13. void USART_Send(volatile char *s);
  14. int PutFile(int ch, FILE *f);
  15. void Send_Charc(volatile char c);
  16. volatile uint16_t delay_count = 0;
  17. uint8_t SYSTICK_ON()
  18. {
  19.    if (SysTick_Config(SystemCoreClock / 1000))
  20.    {   while (1);  }
  21. }
  22. void delay_ms(uint16_t delay_temp)
  23. {
  24.     delay_count = delay_temp;
  25.     while(delay_count) { }
  26. }
  27. int main()
  28. {
  29.     uint32_t RNG_Random = 0;
  30.    
  31.     SystemInit();
  32.     LedInit();
  33.     GPIO_Initialize();
  34.     USART_Initialize();
  35.     SystemCoreClockUpdate();
  36.     SYSTICK_ON();
  37.    
  38.     RCC_AHB2PeriphClockCmd(RCC_AHB2Periph_RNG, ENABLE); //Wlaczenie zegara dla RNG
  39.     RNG_Cmd(ENABLE);
  40.     while(1)
  41.     {
  42.         RNG_Random = RNG_GetRandomNumber();
  43.        
  44.         printf("Wartosc: %zu \n", RNG_Random);
  45.        
  46.         GPIOD->BSRRH = GPIO_Pin_12;
  47.         GPIOD->BSRRH = GPIO_Pin_13;
  48.         GPIOD->BSRRH = GPIO_Pin_14;
  49.         GPIOD->BSRRH = GPIO_Pin_15;
  50.        
  51.         if(RNG_Random < (0xFFFFFFFF >> 4))
  52.         {
  53.                 GPIOD->BSRRL = GPIO_Pin_12;
  54.         }
  55.         else if(RNG_Random < (0xFFFFFFFF >> 4)*2)
  56.         {
  57.                 GPIOD->BSRRL = GPIO_Pin_13;
  58.         }
  59.         else if(RNG_Random < (0xFFFFFFFF >> 4)*3)
  60.         {
  61.                 GPIOD->BSRRL = GPIO_Pin_14;
  62.         }
  63.         else
  64.         {
  65.                 GPIOD->BSRRL = GPIO_Pin_15;
  66.         }
  67.         delay_ms(200);
  68.     }
  69. }
  70. void USART_Initialize(void)
  71. {
  72.      NVIC_InitTypeDef NVIC_InitStruct;
  73.    
  74.      USART_InitTypeDef USART_InitStructure;
  75.      
  76.      NVIC_InitStruct.NVIC_IRQChannel = USART1_IRQn;
  77.    
  78.      RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
  79.      
  80.      USART_InitStructure.USART_BaudRate = 9600;
  81.      USART_InitStructure.USART_WordLength = USART_WordLength_8b;
  82.      USART_InitStructure.USART_StopBits = USART_StopBits_1;
  83.      USART_InitStructure.USART_Parity = USART_Parity_No;
  84.      USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
  85.      USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
  86.      
  87.      USART_Init(USART1, &USART_InitStructure);
  88.      USART_Cmd(USART1, ENABLE);
  89.      
  90.      USART1->CR1 |= USART_CR1_RXNEIE;
  91.    
  92.      NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
  93.      NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1;
  94.      NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1;
  95.      NVIC_Init(&NVIC_InitStruct);
  96. }
  97. void GPIO_Initialize(void)
  98. {
  99.      GPIO_InitTypeDef  GPIO_In;
  100.      RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
  101.      
  102.      //TX dla pinu PB6
  103.      GPIO_In.GPIO_Pin = GPIO_Pin_6;
  104.      GPIO_In.GPIO_PuPd = GPIO_PuPd_UP;
  105.      GPIO_In.GPIO_OType = GPIO_OType_PP;
  106.      GPIO_In.GPIO_Mode = GPIO_Mode_AF;
  107.      GPIO_In.GPIO_Speed = GPIO_Speed_100MHz;
  108.      GPIO_Init(GPIOB, &GPIO_In);
  109.      
  110.      //RX dla pinu PB7
  111.      GPIO_In.GPIO_Pin = GPIO_Pin_7;
  112.      GPIO_In.GPIO_Mode = GPIO_Mode_AF;
  113.      GPIO_In.GPIO_PuPd = GPIO_PuPd_UP;
  114.      GPIO_In.GPIO_OType = GPIO_OType_PP;
  115.      GPIO_In.GPIO_Speed = GPIO_Speed_100MHz;
  116.      GPIO_Init(GPIOB, &GPIO_In);
  117.      GPIO_PinAFConfig(GPIOB, GPIO_PinSource6, GPIO_AF_USART1);
  118.      GPIO_PinAFConfig(GPIOB, GPIO_PinSource7, GPIO_AF_USART1);
  119. }
  120. void USART_Send(volatile char *c)
  121. {
  122.      while(*c)
  123.      {
  124.         while( !(USART1->SR & 0x00000040) );
  125.         USART_SendData(USART1, *c);
  126.         *c++;
  127.      }
  128. }
  129. int fputc(int ch, FILE *f)
  130. {
  131.     volatile char c = ch;
  132.    
  133.         USART1->DR = (uint16_t)(& 0x01FF);
  134.       while (!((USART1)->SR & USART_FLAG_TXE))
  135.         {}
  136.        
  137.     return ch;
  138. }
  139. void Send_Charc(volatile char c)
  140. {
  141.  while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
  142.  USART_SendData(USART1, c);
  143. }
  144. void SysTick_Handler(void)
  145. {
  146.     if(delay_count > 0)
  147.     {
  148.         delay_count--;
  149.     }
  150. }

Bibliografia:

[1] STM32 - RNG - DM00073853