Весной меня отправили на карантин и появилось немного времени, что бы спаять что-нибудь интересное. Выбор пал на вот это устройство.

Конечно же хотелось расширить возможности радиометра и узнать, какие же конкретно радиоактивные изотопы подстерегают меня в повседневной жизни в г. Киев, который находится уж очень близко к ЧЗО.



В статье расскажу, как собирал прибор и что поменял в схемотехнике и прошивке.

Первым делом нужно заказать платы. В материалах к исходной статье есть гербер файлы, поэтому все просто. Заказ сделал на PCBWay и JLCPCB, чтобы сравнить качество. Первый рекомендовать не могу: доставка заняла 3 месяца, крепежные отверстия на платах оказались меньше, чем нужно. Из 5 системных плат 2 оказались бракованными (о чем они мне сообщили в письме). C JLCPCB все вышло хорошо и придраться не к чему.

Компоненты заказывал на Mouser и наборы конденсаторов и резисторов на Али (лень стало подбирать все по емкости и решил просто заказать набор). В качестве SiPM использовал MicroFC 60035 — это самая дорогая часть устройства. На момент заказа стоила 70 долларов на Mouser. С более мелким и дешевым 30035 решил не связываться, испугавшись, что припаять и собрать его будет сложнее.

Вторым главным компонентом устройства, кроме фотоприемника, является сцинтилляционный кристалл. И здесь большое поле для модификаций. Найти используемый автором CsI(Tl) маленьких размеров дешевле 90 долларов мне не удалось. Поэтому остановился на NaI(Tl) 10x40мм c ебея за 32 доллара с доставкой. Поиск такого кристалла — это само по себе увлекательное занятие, здесь главное не спешить. Все поисковые запросы в гугле вели меня к Евгению с Украины, но прозрачных кристаллов для спектрометрии у него просто нет. Все, что он присылал имело неприятный желтый оттенок урины.

И вот, все детальки и платы пришли, можно начинать паять. Первым делом решил спаять аналоговую плату. Здесь все без приключений, главное не забыть припаять резистор, место под которое не разведено (внимательно читаем советы по сборке к оригинальной статье).

В системную плату пришлось внести следующие изменения: По даташиту LM2733Y, выходное напряжение не зависит от входного, соответственно подстраивать нечего. Берем из того же даташита формулу R1 = R2 X (VOUT/1.23 ? 1) и из того, что нашлось, ставим R13 = 1.8K, R12 = 12K, R11 = 300K. На выходе стабильно 28.18В (пробовал подавать 2.5В, 5В — на выходе все стабильно). После подключения дисплея устройство стало выдавать намного большее число импульсов, чем есть на самом деле. Исправить удалось изменением цепи питания дисплея: вход переключателя DA6 подключаем ко входу DA3. На выходе DA6 ставим преобразователь на 5В (у меня под рукой оказался pololu cj7032) и уже от него питаем дисплей. При таком подключении все помехи сразу ушли.

В качестве дисплея взял nx4024t032: он меньше, дешевле, меньше потребляет и главное, был доступен в локальном магазине. Прошивку я все равно планировал менять, об этом ниже.

После пайки отмывал схемы изопропиловым спиртом в УЗ ванне. После спирта стоит отмыть дистиллированной водой в той же ванне и просушить в духовке при температуре около 70-80 градусов.

Теперь пришла пора сделать самое интересное: подключить датчик и посмотреть, что же получится. MicroFC 60035 почти идеально припаивается к куску макетной платы 3x3 отверстия: лудим угловые отверстия и припаиваем датчик феном. С обратной стороны макетки припаиваем провода. Вот так это выглядит.



Вот так выглядит кучка плат и деталек без корпуса.



Внимательный читатель может заметить, что процессор я взял STM32L152CBT6A — чуть больше памяти и доступен локально.

Корпус сделал в Fusion 360 и напечатал на 3D принтере. Вот ссылка на проект.

Вот так все выглядит уже в сборе:



Настало время для самого интересного — изменений в прошивке. Мы же хотим сделать именно сцинтилляционный детектор, а не просто радиометр. Для этого нам понадобится использовать DMA с ADC (ADC в этом процессоре один, но есть переключатель входов). А входов у нас два: SP и вольтаж батареи. DMA нужно для ускорения всего процесса. Так же хочу обратить внимание на количество циклов измерений ADC_SampleTime, при 48 и более у меня ничего не получилось. 4 цикла показали наиболее стабильный результат.

Меняем код инициализации ADC следующим образом:

void initADC(void) {
	/* PWR_CTRL and CHG_STAT clock enable */
	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOB, ENABLE);

	/* UBAT input pin configuration */
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12|GPIO_Pin_15;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_40MHz;
	GPIO_Init(GPIOB, &GPIO_InitStructure);

	/*------------------------ DMA1 configuration ------------------------------*/
	/* Enable DMA1 clock */
	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
	/* DMA1 channel1 configuration */
	DMA_DeInit(DMA1_Channel1);
	DMA_InitStructure.DMA_PeripheralBaseAddr = ADC1_DR_ADDRESS;
	DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&ADC_ConvertedValue[0];
	DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
	DMA_InitStructure.DMA_BufferSize = 2;
	DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
	DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
	DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
	DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
	DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
	DMA_InitStructure.DMA_Priority = DMA_Priority_High;
	DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
	DMA_Init(DMA1_Channel1, &DMA_InitStructure);
	/* Enable DMA1 channel1 */
	DMA_Cmd(DMA1_Channel1, ENABLE);
	/*----------------- ADC1 configuration with DMA enabled --------------------*/
	/* Enable The HSI (16Mhz) */
	RCC_HSICmd(ENABLE);
	/* Check that HSI oscillator is ready */
	while
	(!RCC_GetFlagStatus(RCC_FLAG_HSIRDY));
	/* Enable ADC1 clock */
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
	/* ADC1 Configuration -----------------------------------------------------*/
	ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
	ADC_InitStructure.ADC_ScanConvMode = ENABLE;
	ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
	ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
	ADC_InitStructure.ADC_ExternalTrigConv = 0;
	ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
	ADC_InitStructure.ADC_NbrOfConversion = 2;
	ADC_Init(ADC1, &ADC_InitStructure);
	/* Enable temperature sensor and Vref */
	ADC_TempSensorVrefintCmd(ENABLE);
	//ADC_TempSensorVrefintCmd(DISABLE);
	/* ADC1 regular channel configuration */
	ADC_RegularChannelConfig(ADC1, SP_ADC_CHANNEL, 1, ADC_SampleTime_4Cycles);
	ADC_RegularChannelConfig(ADC1, UBAT_ADC_CHANNEL, 2, ADC_SampleTime_4Cycles);

	/* Enable the request after last transfer for DMA Circular mode */
	ADC_DMARequestAfterLastTransferCmd(ADC1, ENABLE); /* Causes problem.. */
	/* Define delay between ADC1 conversions */
	ADC_DelaySelectionConfig(ADC1, ADC_DelayLength_None);
	/* Enable ADC1 Power Down during Delay */
	ADC_PowerDownCmd(ADC1, ADC_PowerDown_Idle_Delay, ENABLE);
	/* Enable ADC1 DMA */
	ADC_DMACmd(ADC1, ENABLE);
	/* Enable ADC1 */
	ADC_Cmd(ADC1, ENABLE);

	while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_ADONS));

	ADC_SoftwareStartConv(ADC1);
}

Теперь нам нужно попросить контроллер сделать измерения сигнала каждый раз, когда мы видим импульс на входе TRIG:

void EXTI0_IRQHandler(void) // Обработчик импульсов сцинтиллятора
{
	uint16_t i;
    /* Проверяем, откуда у нас прерывание */
    if (EXTI_GetITStatus(EXTI_Line0) != RESET) {
        if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_0) != 1) {
            // Убеждаемся, что прерывание прилетело по нужной линии, а не с клавиатуры, например.
        	if(Mute == false) {
        		GPIOB->ODR &= ~GPIO_ODR_ODR_3;
        	}
        	if(DMA_GetFlagStatus(DMA1_FLAG_TC1)) {
        		ADC_SoftwareStartConv(ADC1);
        	}

        	counter++;
            Delay(20); // ждем, пока не кончится дребезжащий хвост импульса
            if(Mute == false) {
            	GPIOB->ODR |= GPIO_ODR_ODR_3;
            }

            if(	(DMA_GetFlagStatus(DMA1_FLAG_TC1))) {
				i = ADC_ConvertedValue[0];
				adcBatValue += ADC_ConvertedValue[1];
				if (i >= SPECTRE_START_BIT && i < (SPECTRE_RES + SPECTRE_START_BIT)) {
				i = i-SPECTRE_START_BIT;
				spectre[i] ++;

				if(spectre[i] > spectreMax) {
					spectreMax = spectre[i];
				}

				if(spectreMax > SPECTRE_MAX_VAL) {
					spectreMax = 0;
					resetSpectre();
				}

			}
		}
        }
        /* Не забываем сбросить флаг прерывания */
        EXTI_ClearITPendingBit(EXTI_Line0);
    }
}

Здесь мы запускаем измерение, увеличиваем счетчик импульсов и сохраняем полученный результат измерения в массив для дальнейшей обработки и вывода на экран.

Кроме этого, в прошивке поменял назначение кнопок: вверх/вниз изменяет яркость дисплея, кнопка меню показывает спектр, последняя кнопка включает и выключает звук. Экрана у нас только два: основной поисковый экран с графиком интенсивности счетных импульсов и пустой экран для вывода спектрограммы. Спектрограмму выводим сразу в линейном и логарифмическом масштабе, так удобнее смотреть.

Вот такие так выглядят спектрограммы фона и америций-241 из датчика дыма.



На спектре от бананов (первое изображение в статье) можно увидеть еле заметный калиевый бугор, но без свинцового домика измерить его очень проблематично.

Модифицированные прошивка дисплея и микроконтроллера доступны на Google Drive.

При создании устройства мне пригодились следующие материалы:

habr.com/ru/post/456878
habr.com/ru/post/487510 и habr.com/ru/post/487518
misrv.com/ultra-micron-module-as
www.youtube.com/watch?v=I8-h8mLnexw