Фильтрация звука на STM32 с использованием КИХ фильтра

Давным-давно, в начале перестройки начали появляться у народа забавные тайваньские штучки, к примеру, часы электронные с кучей мелодий, или вот брелок к ключам, который на свист забывшего, где лежат эти ключи человека, откликался своим ответным пронзительным писком. В брелоке находился пьезо-излучатель, он же и микрофон, пара маленьких батареек и платка с залитой клеем микросхемой.




Читать дальше

Дружим программу CANHacker и модуль 2CAN от Starline

Прочитал замечательную статью на Хабре, habrahabr.ru/post/256493/:




Читать дальше

Использование модулей CAN на STM32 для разных целей

В последнее время, к сожалению, выросла цена на многие импортные радиодетали, в том числе и на отладочные платы с микроконтроллерами. А потребность в изготовлении разных поделок к счастью не пропала. Волей случая у меня в руках оказалось несколько интересных модулей от компании Starline, которая выпускает автомобильные сигнализации и много других полезных вещей (Можете поспрашивать у установщиков сигнализаций, или на сайте производителя). Целей раскрыть секреты работы этих модулей не стояло. Но ввиду их хорошего изготовления и оснащения оставить пропадать их без дела наше время тоже нехорошо.
Вкратце о модулях:
Модуль CAN — STM32F103RBT8 + SST25V016 + TJA1042, силовые ключи, микросхемы питания.
Модуль 2CAN — STM32F105RBT8 + SST25V032 + TJA1048, микросхемы питания.





Читать дальше

Keil MDK Version 5 - бесплатно для STM32L0 and STM32F0

Пробовал Keil и случайно наткнулся на страницу на keil.com
Оказывается для STM32L0 и STM32F0 они дают среду бесплатно и без ограничений:
http://www2.keil.com/stmicroelectronics-stm32/mdk

STM32F030F4 задержки

Функция delay() при помощи таймера TIM16

Сперва инициализация

void TIM16_init(void){
  NVIC_InitTypeDef NVIC_InitStructure;
  TIM_TimeBaseInitTypeDef TIM_InitStructure; 

  RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM16, ENABLE);

  NVIC_InitStructure.NVIC_IRQChannel = TIM16_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPriority = 0x01;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);  
  
  TIM_InitStructure.TIM_Period = 1;
  TIM_InitStructure.TIM_Prescaler = 400;
  TIM_InitStructure.TIM_CounterMode = TIM_CounterMode_Up;
  TIM_InitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
  TIM_InitStructure.TIM_RepetitionCounter = 0;
  TIM_TimeBaseInit(TIM16, &TIM_InitStructure);

  TIM_ITConfig(TIM16, TIM_IT_Update, ENABLE);
  TIM_Cmd(TIM16, ENABLE);
}


400 реально мэджик нумбер подобраный осцилографом. )) Как оно рассчитывается в теории понятно, но на практике что-то не очень. Вообщем это дает нам прерывание таймера каждые 100 микросекунд.


static volatile uint16_t delay_counter = 0;
void TIM16_IRQHandler(void) {
    if (TIM_GetITStatus(TIM16, TIM_IT_Update) != RESET) {
        delay_counter++;
        TIM_ClearITPendingBit(TIM16, TIM_IT_Update);
    }
}


И собственно функции задержки:

void delay_100us(void) {    // задержка 100 uS
  delay_counter = 0;
  while (!delay_counter);
}

void delay_ms(int ms) {    // задержка N mS
  int i;
  for(i=0;i<ms*10;i++) {
    delay_100us();
  }
}


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

Использвание (мигание светодиодом):

  while(1)
  {
     GPIO_SetBits(GPIOA, GPIO_Pin_4);
     delay_ms(500);
     GPIO_ResetBits(GPIOA, GPIO_Pin_4);
     delay_ms(500);
  }

STM32F030F4 прерывания

Прерывание дело несложное. Единственный ньюанс — не забудьте подключить файлы startup_stm32f030.s и system_stm32f0xx.c (находятся в архиве с SPL, папка STM32F0xx_StdPeriph_Lib_V1.5.0\Libraries\CMSIS\Device\ST\STM32F0xx\Source\Templates\), иначе прерывание закончится вызовом HardFault_Handler.

Например, прерывание по кнопке. Кнопку подключаем к PA0 и земле. И от PA0 подтягивающий резистор к плюсу питания.

Инициалазация

  EXTI_InitTypeDef   EXTI_InitStructure;
  NVIC_InitTypeDef   NVIC_InitStructure;

  /* Configure PA0 pin as input floating */
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
  GPIO_Init(GPIOA, &GPIO_InitStructure);

  /* Enable SYSCFG clock */
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);
  /* Connect EXTI0 Line to PA0 pin */
  SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOA, EXTI_PinSource0);

  /* Configure EXTI0 line */
  EXTI_InitStructure.EXTI_Line = EXTI_Line0;
  EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
  EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;
  EXTI_InitStructure.EXTI_LineCmd = ENABLE;
  EXTI_Init(&EXTI_InitStructure);

  /* Enable and set EXTI0 Interrupt */
  NVIC_InitStructure.NVIC_IRQChannel = EXTI0_1_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPriority = 0x00;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);


Обработчик

void EXTI0_1_IRQHandler(void)
{
  if(EXTI_GetITStatus(EXTI_Line0) != RESET) {

    // делаем что-нибудь полезное  

    /* Clear the EXTI line 0 pending bit */
    EXTI_ClearITPendingBit(EXTI_Line0);
  }
}

STM32F030F4 SPI

Минздрав предупреждает: данный материал может оскорбить чувства профессионалов и зануд.



Читать дальше

STM32F030F4 инициализируем ADC

ADC на PA0

Инициализация:
void ADC_Config(void)
{
  ADC_InitTypeDef     ADC_InitStructure;
  GPIO_InitTypeDef    GPIO_InitStructure;

  RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
  
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 ;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;
  GPIO_Init(GPIOA, &GPIO_InitStructure);
  
  ADC_DeInit(ADC1);
  
  ADC_StructInit(&ADC_InitStructure);
  
  ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
  ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; 
  ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
  ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
  ADC_InitStructure.ADC_ScanDirection = ADC_ScanDirection_Upward;
  ADC_Init(ADC1, &ADC_InitStructure); 
  
  ADC_ChannelConfig(ADC1, ADC_Channel_0 , ADC_SampleTime_239_5Cycles);
  ADC_GetCalibrationFactor(ADC1);
  ADC_Cmd(ADC1, ENABLE);     
  
  while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_ADRDY)); 
  
  ADC_StartOfConversion(ADC1);
}


Использование:

ADC_Config();
while(1) {
    while(ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET);
    ADCValue = ADC_GetConversionValue(ADC1);
}


Вместо ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; можно написать ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;, тогда перед каждой оцифровкой надо будет вызывать ADC_StartOfConversion(ADC1);

Заодно есть вопрос. Подключаю PA0 через делитель к +3.3V, гоняю по циклу ADC_GetConversionValue(). Оцифрованые значения имеют разбежку +/-10. Это нормально поведение АЦП или я что-то не так делаю?

Шрифты с GLCD Font Creator на коленке

Известная тема графических дисплеев — необходимость носить шрифты с собой.

Задача:
— IAR, STM32;
— есть дисплей 128х64 OLED(монохром);
— нужен один хороший шрифт с Кириллицей;
— нужна приемлемая читаемость и размер;
— нужна хорошая плотность записи на экране;
— нужно вводить строки прямо в коде программы, не задумываясь над кодировками.


Читать дальше

Приличный (без bit-banging) и дешёвый SPI-flash программатор, c DMA SPI и USB на основе flashrom и maple-mini (stm32).

В общем, понадобилось слить прошивку и прошить роутер TP-link (пересадить его с S25FL032A/P на M25P128). В итоге в сусеках интернета был найден на гитхабе проект github.com/dword1511/stm32-vserprog, который реализует то, что и указано в заголовке. Учитывя, что стоит она $4.2, и она у меня уже есть, я был очень рад.


Читать дальше