Очередная багофича HAL
Наткнулся на новый косяк библиотеки HAL в функции HAL_I2S_Transmit. Есть у нее параметр uint16_t Size, который удваивается в случае работы с данными 24 или 32 бита
Проблема в том, что переменные TxXferSize и TxXferCount имеют тип uint16_t. И если на вход HAL_I2S_Transmit передать размер 0x8000 и более, то после сдвига влево результат превращается в тыкву.
// stm32f4xx_hal_i2s.c line 537
if((tmp1 == I2S_DATAFORMAT_24B) || (tmp1 == I2S_DATAFORMAT_32B))
{
hi2s->TxXferSize = (Size << 1U);
hi2s->TxXferCount = (Size << 1U);
}
else
{
hi2s->TxXferSize = Size;
hi2s->TxXferCount = Size;
}
Проблема в том, что переменные TxXferSize и TxXferCount имеют тип uint16_t. И если на вход HAL_I2S_Transmit передать размер 0x8000 и более, то после сдвига влево результат превращается в тыкву.
// stm32f4xx_hal_i2s.h line 110
typedef struct __I2S_HandleTypeDef
{
SPI_TypeDef *Instance; /*!< I2S registers base address */
I2S_InitTypeDef Init; /*!< I2S communication parameters */
uint16_t *pTxBuffPtr; /*!< Pointer to I2S Tx transfer buffer */
__IO uint16_t TxXferSize; /*!< I2S Tx transfer size */
__IO uint16_t TxXferCount; /*!< I2S Tx transfer Counter */
SWM050I2P7 - ARM на 8 ног
Раз у нас сегодня день странных китайских МК, то ловите еще один — SWM050I2P7-65. Заинтересовал меня в первую очередь тем что это восьминогий ARM в корпусе TSSOP. Цена на lcsc.com от $0.4262 если брать поштучно или $0.3315 от 10 шт. Купил образцы, но пока не дошли руки подключить к программатору.
Характеристики думаю понятны и без перевода

Мануалы, SDK и т.д. лежат на сайте производителя www.synwit.cn/support.html (пользуйтесь переводчиком в браузере). Нашлась поддержка для IAR и Keil, но повторюсь на практике пока не проверялось.
Так же есть вариант SWM050Q2S7-65 в корпусе SSOP-16
Характеристики думаю понятны и без перевода

Мануалы, SDK и т.д. лежат на сайте производителя www.synwit.cn/support.html (пользуйтесь переводчиком в браузере). Нашлась поддержка для IAR и Keil, но повторюсь на практике пока не проверялось.
Так же есть вариант SWM050Q2S7-65 в корпусе SSOP-16
Если не дружат HAL и SDIO
Потомкам, которые это нагуглят. Если вы третий день пытаетесь запустить FatFS SDIO в HAL STM32F4 и ничего не получается, то включите DMA. Версия HAL 1.21

Включать раздельные DMA не обязательно, можно один SDIO. В общем пробуйте, у вас получится.

Включать раздельные DMA не обязательно, можно один SDIO. В общем пробуйте, у вас получится.
- 0
- 30 сентября 2018, 22:10
- aliaksei
- Оставить комментарий
STM8 в автопроме
Достался мне как запчасть блок управления полным приводом и подогревом сидений от УАЗ Патриот. Естественно, я его вскрыл и обнаружил внутри маленькую радость — STM8S003F3. Прошивку прочитать не удалось, конечно.
Читать дальше
Читать дальше
STM8S103 и энкодер
На примере STM8S103F3
Инициализация
0xFFFF максимальное значение, до которого будет крутиться энкодер. Далее переходит в ноль и начинается все сначала.
Получение текущего положения
Подключение

И не забываем
Инициализация
TIM1_TimeBaseInit(0, TIM1_COUNTERMODE_UP, 0xFFFF, 0);
TIM1_EncoderInterfaceConfig(TIM1_ENCODERMODE_TI12, TIM1_ICPOLARITY_FALLING, TIM1_ICPOLARITY_FALLING);
TIM1_Cmd(ENABLE);
0xFFFF максимальное значение, до которого будет крутиться энкодер. Далее переходит в ноль и начинается все сначала.
Получение текущего положения
position = TIM1_GetCounter();
Подключение

И не забываем

STM32F030F4 задержки
Функция delay() при помощи таймера TIM16
Сперва инициализация
400 реально мэджик нумбер подобраный осцилографом. )) Как оно рассчитывается в теории понятно, но на практике что-то не очень. Вообщем это дает нам прерывание таймера каждые 100 микросекунд.
И собственно функции задержки:
Код мне кажется не очень оптимальным, — вот как чувствую грабли, — послушал бы ваши замечания.
Использвание (мигание светодиодом):
Сперва инициализация
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 подтягивающий резистор к плюсу питания.
Инициалазация
Обработчик
Например, прерывание по кнопке. Кнопку подключаем к 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
Инициализация:
Использование:
Вместо ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; можно написать ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;, тогда перед каждой оцифровкой надо будет вызывать ADC_StartOfConversion(ADC1);
Заодно есть вопрос. Подключаю PA0 через делитель к +3.3V, гоняю по циклу ADC_GetConversionValue(). Оцифрованые значения имеют разбежку +/-10. Это нормально поведение АЦП или я что-то не так делаю?
Инициализация:
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. Это нормально поведение АЦП или я что-то не так делаю?