Для того, чтобы получить псевдослучайные числа на МК, можно использовать его АЦП: как минимум один младший бит непременно будет плавать. Чтобы улучшить "энтропию", можно прицепить к какому-нибудь внешнему входу АЦП небольшую антенну. А можно просто использовать внутренние каналы: измерения температуры и напряжения. Настроим на STM32F103 АЦП для работы в однократном режиме:
void adc_setup(){
//GPIOC->CRL |= CRL(0, CNF_ANALOG|MODE_INPUT); // uncomment to use ADC10 @PC0
uint32_t ctr = 0;
// Enable clocking
RCC->APB2ENR |= RCC_APB2ENR_ADC1EN;
RCC->CFGR &= ~(RCC_CFGR_ADCPRE);
RCC->CFGR |= RCC_CFGR_ADCPRE_DIV8; // ADC clock = RCC / 8
// sampling time - 7.5 cycles for channels 10, 16 and 17
ADC1->SMPR1 = ADC_SMPR1_SMP10_0 | ADC_SMPR1_SMP16_0 | ADC_SMPR1_SMP17_0;
// single mode, enable vref & Tsens; wake up ADC
ADC1->CR2 |= ADC_CR2_TSVREFE | ADC_CR2_ADON;
// wait for Tstab - at least 1us
while(++ctr < 0xff) nop();
// calibration
ADC1->CR2 |= ADC_CR2_RSTCAL;
ctr = 0; while((ADC1->CR2 & ADC_CR2_RSTCAL) && ++ctr < 0xfffff);
ADC1->CR2 |= ADC_CR2_CAL;
ctr = 0; while((ADC1->CR2 & ADC_CR2_CAL) && ++ctr < 0xfffff);
}
Выбор номера канала выполняется при помощи регистра SQR3. В данном случае нам не нужно, чтобы АЦП молотил постоянно. Иначе можно было бы настроить его в связке с DMA. Ну, а дальше просто читаем младший бит то температуры, то напряжения, заполняем 32-битное число и "мешаем" биты по алгоритму XOR shift из википедии:
uint32_t getRand(){
uint32_t r = 0;
for(int i = 0; i < 16; ++i){
r <<= 1;
r |= (getADCval(0) & 1);
r <<= 1;
r |= (getADCval(1) & 1);
}
r ^= r << 13;
r ^= r >> 17;
r ^= r << 5;
return r;
}
И если первоначальные данные не очень-то похожи на равномерное распределение, то после XOR shift получается очень даже ничего. Собранные 10000 псевдослучайных чисел:
Эти же значения в отсортированном виде:
Ну и гистограмма из распределения старших восьми битов:
Меня полученный результат вполне устраивает. И, в отличие от обычного генератора псевдослучайных чисел, здесь можно гарантировать, что повторяющихся последовательностей не будет.