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:
- RCC_AHB2PeriphClockCmd(RCC_AHB2Periph_RNG, ENABLE);
- //lub na rejestrach
- RCC->AHB2ENR |= RCC_AHB2ENR_RNGEN; //((uint32_t)0x00000040)
- __DSB();
Włączenie modułu odbywa się za pomocą funkcji RNG_Cmd(), która wygląda następująco:
- void RNG_Cmd(FunctionalState NewState)
- {
- //Sprawdzenie parametrow
- assert_param(IS_FUNCTIONAL_STATE(NewState));
- if (NewState != DISABLE)
- {
- //Wlaczenie RNG
- RNG->CR |= RNG_CR_RNGEN;
- }
- else
- {
- //Wylaczenie RNG
- RNG->CR &= ~RNG_CR_RNGEN;
- }
- }
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();
- uint32_t RNG_GetRandomNumber(void)
- {
- return RNG->DR;
- }
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.
- #include "stm32f4xx.h"
- #include "stm32f4xx_rcc.h"
- #include "stm32f4xx_usart.h"
- #include "stdio.h"
- #include "misc.h"
- struct __FILE {
- int parametr;
- };
- FILE __stdout;
- void send_char(char);
- void USART_Initialize(void);
- void GPIO_Initialize(void);
- void USART_Send(volatile char *s);
- int PutFile(int ch, FILE *f);
- void Send_Charc(volatile char c);
- volatile uint16_t delay_count = 0;
- uint8_t SYSTICK_ON()
- {
- if (SysTick_Config(SystemCoreClock / 1000))
- { while (1); }
- }
- void delay_ms(uint16_t delay_temp)
- {
- delay_count = delay_temp;
- while(delay_count) { }
- }
- int main()
- {
- uint32_t RNG_Random = 0;
- SystemInit();
- LedInit();
- GPIO_Initialize();
- USART_Initialize();
- SystemCoreClockUpdate();
- SYSTICK_ON();
- RCC_AHB2PeriphClockCmd(RCC_AHB2Periph_RNG, ENABLE); //Wlaczenie zegara dla RNG
- RNG_Cmd(ENABLE);
- while(1)
- {
- RNG_Random = RNG_GetRandomNumber();
- printf("Wartosc: %zu \n", RNG_Random);
- GPIOD->BSRRH = GPIO_Pin_12;
- GPIOD->BSRRH = GPIO_Pin_13;
- GPIOD->BSRRH = GPIO_Pin_14;
- GPIOD->BSRRH = GPIO_Pin_15;
- if(RNG_Random < (0xFFFFFFFF >> 4))
- {
- GPIOD->BSRRL = GPIO_Pin_12;
- }
- else if(RNG_Random < (0xFFFFFFFF >> 4)*2)
- {
- GPIOD->BSRRL = GPIO_Pin_13;
- }
- else if(RNG_Random < (0xFFFFFFFF >> 4)*3)
- {
- GPIOD->BSRRL = GPIO_Pin_14;
- }
- else
- {
- GPIOD->BSRRL = GPIO_Pin_15;
- }
- delay_ms(200);
- }
- }
- void USART_Initialize(void)
- {
- NVIC_InitTypeDef NVIC_InitStruct;
- USART_InitTypeDef USART_InitStructure;
- NVIC_InitStruct.NVIC_IRQChannel = USART1_IRQn;
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
- USART_InitStructure.USART_BaudRate = 9600;
- USART_InitStructure.USART_WordLength = USART_WordLength_8b;
- USART_InitStructure.USART_StopBits = USART_StopBits_1;
- USART_InitStructure.USART_Parity = USART_Parity_No;
- USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
- USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
- USART_Init(USART1, &USART_InitStructure);
- USART_Cmd(USART1, ENABLE);
- USART1->CR1 |= USART_CR1_RXNEIE;
- NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
- NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1;
- NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1;
- NVIC_Init(&NVIC_InitStruct);
- }
- void GPIO_Initialize(void)
- {
- GPIO_InitTypeDef GPIO_In;
- RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
- //TX dla pinu PB6
- GPIO_In.GPIO_Pin = GPIO_Pin_6;
- GPIO_In.GPIO_PuPd = GPIO_PuPd_UP;
- GPIO_In.GPIO_OType = GPIO_OType_PP;
- GPIO_In.GPIO_Mode = GPIO_Mode_AF;
- GPIO_In.GPIO_Speed = GPIO_Speed_100MHz;
- GPIO_Init(GPIOB, &GPIO_In);
- //RX dla pinu PB7
- GPIO_In.GPIO_Pin = GPIO_Pin_7;
- GPIO_In.GPIO_Mode = GPIO_Mode_AF;
- GPIO_In.GPIO_PuPd = GPIO_PuPd_UP;
- GPIO_In.GPIO_OType = GPIO_OType_PP;
- GPIO_In.GPIO_Speed = GPIO_Speed_100MHz;
- GPIO_Init(GPIOB, &GPIO_In);
- GPIO_PinAFConfig(GPIOB, GPIO_PinSource6, GPIO_AF_USART1);
- GPIO_PinAFConfig(GPIOB, GPIO_PinSource7, GPIO_AF_USART1);
- }
- void USART_Send(volatile char *c)
- {
- while(*c)
- {
- while( !(USART1->SR & 0x00000040) );
- USART_SendData(USART1, *c);
- *c++;
- }
- }
- int fputc(int ch, FILE *f)
- {
- volatile char c = ch;
- USART1->DR = (uint16_t)(c & 0x01FF);
- while (!((USART1)->SR & USART_FLAG_TXE))
- {}
- return ch;
- }
- void Send_Charc(volatile char c)
- {
- while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
- USART_SendData(USART1, c);
- }
- void SysTick_Handler(void)
- {
- if(delay_count > 0)
- {
- delay_count--;
- }
- }
Bibliografia:
[1] STM32 - RNG - DM00073853