где то у вас с настройкой TIM нетак .
Hапример - > TIM14->ARR = 8; / " /* (2) Set ARR = 8, as timer clock is 1MHz the period is 9 us */"
У вас же куски с разных примеров надёрганы ? Bозьмите код про back_lite , там всё работает.
Чтобы менять шим, достаточно просто CCRx переписывать. Другие регистры менять не нужно.
Hельзя задавать параметры CCRx = 0 , CCRx = ARR .
100% включить /выключить шим ( если это так важно) можно командой SPL TIM_ForcedOC1Config().
typedef enum {FAILED = 0, PASSED = !FAILED} TestStatus;
#ifdef STM32F072
#define FLASH_PAGE_SIZE ((uint32_t)0x00000800) /* FLASH Page Size */
#define FLASH_USER_START_ADDR ((uint32_t)0x08009000) /* Start @ of user Flash area */
#define FLASH_USER_END_ADDR ((uint32_t)0x08020000) /* End @ of user Flash area */
#elif defined (STM32F091)
#define FLASH_PAGE_SIZE ((uint32_t)0x00000800) /* FLASH Page Size */
#define FLASH_USER_START_ADDR ((uint32_t)0x08009000) /* Start @ of user Flash area */
#define FLASH_USER_END_ADDR ((uint32_t)0x08040000) /* End @ of user Flash area */
#else
#define FLASH_PAGE_SIZE ((uint32_t)0x00000400) /* FLASH Page Size */
#define FLASH_USER_START_ADDR ((uint32_t)0x08006000) /* Start @ of user Flash area */
#define FLASH_USER_END_ADDR ((uint32_t)0x08007000) /* End @ of user Flash area */
#endif /* STM32F072 */
#define DATA_32 ((uint32_t)0x12345678)
uint32_t EraseCounter = 0x00, Address = 0x00;
uint32_t Data = 0x3210ABCD;
uint32_t NbrOfPage = 0x00;
__IO FLASH_Status FLASHStatus = FLASH_COMPLETE;
__IO TestStatus MemoryProgramStatus = PASSED;
#ifdef USE_FULL_ASSERT
/**
* @brief Reports the name of the source file and the source line number
* where the assert_param error has occurred.
* @param file: pointer to the source file name
* @param line: assert_param error line source number
* @retval None
*/
void assert_failed(uint8_t* file, uint32_t line)
{
/* User can add his own implementation to report the file name and line number,
ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
/* Infinite loop */
while (1)
{
}
}
#endif
void Writetoflash(void)
{
/* Unlock the Flash to enable the flash control register access *************/
FLASH_Unlock();
/* Program the user Flash area word by word
(area defined by FLASH_USER_START_ADDR and FLASH_USER_END_ADDR) ***********/
Address = FLASH_USER_START_ADDR;
while (Address < FLASH_USER_END_ADDR)
{
if (FLASH_ProgramWord(Address, DATA_32) == FLASH_COMPLETE)
{
Address = Address + 4;
}
else
{
/* Error occurred while writing data in Flash memory.
User can add here some code to deal with this error */
while (1)
{
}
}
}
/* Lock the Flash to disable the flash control register access (recommended
to protect the FLASH memory against possible unwanted operation) *********/
FLASH_Lock();
/* Check if the programmed data is OK
MemoryProgramStatus = 0: data programmed correctly
MemoryProgramStatus != 0: number of words not programmed correctly ******/
Address = FLASH_USER_START_ADDR;
MemoryProgramStatus = PASSED;
while (Address < FLASH_USER_END_ADDR)
{
Data = *(__IO uint32_t *)Address;
if (Data != DATA_32)
{
MemoryProgramStatus = FAILED;
}
Address = Address + 4;
}
}
void Eraseflash(void)
{
/* Unlock the Flash to enable the flash control register access *************/
FLASH_Unlock();
/* Erase the user Flash area
(area defined by FLASH_USER_START_ADDR and FLASH_USER_END_ADDR) ***********/
/* Clear pending flags (if any) */
FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPERR);
/* Define the number of page to be erased */
NbrOfPage = (FLASH_USER_END_ADDR - FLASH_USER_START_ADDR) / FLASH_PAGE_SIZE;
/* Erase the FLASH pages */
for(EraseCounter = 0; (EraseCounter < NbrOfPage) && (FLASHStatus == FLASH_COMPLETE); EraseCounter++)
{
if (FLASH_ErasePage(FLASH_USER_START_ADDR + (FLASH_PAGE_SIZE * EraseCounter))!= FLASH_COMPLETE)
{
/* Error occurred while sector erase.
User can add here some code to deal with this error */
while (1)
{
}
}
}
/* Lock the Flash to disable the flash control register access (recommended
to protect the FLASH memory against possible unwanted operation) *********/
FLASH_Lock();
}
Имеются мелодии для ATmega88PA-AU, одна функция nota, сами мелодии и настройка таймера с обработчиком прерывания. Нужно перенести мелодии под stm32. Как правильно настроить таймер.
C AЦП - программу нужно поправить под вашу схему.
У вас два канала ? Время выборки будет ~17us . Так и нужно ?
АЦП у вас работает постоянно , а считаваете вы с него толко с одного канала.
Если нжны данные с двух каналов , то нужно или DMA настроить - это во всех примерах есть ,
или давать команду софтом на каждое преобразование.
с таймерами полная каша.
если прескалер настривается на 31250 гц , то PRS = 20000000 / 31250 = 640.
Hоты, нaверное, проще всего генерировать, если настроить ШИМ на 50 % и менять прескалер. Спойлерэто из рабочего проекта , ненужное вам - в комментах
и перенастроить c 4 на 2 канала
void ADC_GetSlowSensorsData(void)
{
/*
1. Prefix : Switch ADC from sampling of the fast sensor by DMA
to single shot measurements of the slow sensors.
2. Get ADC samples from all the temperature sensors.
Hоты, нaверное, проще всего генерировать, если настроить ШИМ на 50 % и менять прескалер.
Нифига не проще и не правильно. Прескалером можно задавать только октаву. ARR должна задавать саму ноту. CCR задаёт 50 % ШИМ. Юзая DMAR можно из буфера выталкивать всю эту канитель одновременно.
Чтобы замутить оркестр можно поискать статьи по OSA tester или testerplus. Там на пальцах раскидывалось что к чему.
Вы же прескалером не пополам частоту делите . Если 16 бит таймер , ARR = 4 , CCR = 2 , то для полосы 50 ~ 3500 вполне всё равно .
На ноту не так уверенно попадаешь , но зато проще.
Три регистра менять, конечно , правильно , но человек и с одним разобраться не может.
Как освоит - потом и в трех сам поменяет, без проблем.
С его подходом, кстати , и если тон генерировать, а не waveform, не обязательно вредно с ДМА связываться.
Можно и процессором менять, времени вполне хватает.
pixar писал(а):
С его подходом, кстати , и если тон генерировать, а не waveform, не обязательно вредно с ДМА связываться.
Можно и процессором менять, времени вполне хватает.
Вредно давать вредные советы а не с ДМА связываться. Как и вредно без надобности торчать в программных задержках.
То же самое, АЦП не работает. На индикаторе постоянно отображается цифра 9 если по условию if значение больше 255, т.е. АЦП настроен на 8 бит, а значение превышено. На вход пина подается от 3В до 3.6В. GPIO перенастроил. Stm32 настроен на 20 МГц. Спойлер
5 ногу VDDA надо к 3.5V подключить, как пример см. схему тут: https://andybrown.me.uk/2015/10/31/stm32f042dev/
з.ы. проверьте на вашей схеме как электролитические конденсаторы подключены - полярность как попало
Подключил 5 пин к +Vdd. Теперь проблема в том, что при уменьшении напряжения питания с 4В до 3В, опорное напряжение тоже уменьшается и значение в регистре АЦП не меняется. В даташите что-то написано про Vrefint и ADC_IN17. Но как его настроить к примеру на 2.7В.
в процессоре есть регистр , в котором хранится калиброванное значение внутреней опоры, снятое своим АЦП при питании 3.3вольт +/-1% .
Если измерять внутренюю опору при нестабильном AVdd и сравнивать результат с калиброванным значением, считываемым из регистра процессора , то можно просчитать реальное напряжение питания AVdd и учитывать его изменение при расчёте напряжения на входе АЦП. Процесс итерационный, AVdd_calc сходится после двух-трех итераций.
Точность не очень, у меня даёт , например, расчётное 3.30~3.35 вольта при реальном 3.25.
Но если батарейка плавает , то хоть что-то. Спойлер#define ADC_FULL_SCALE 4095
#define VDDA_ADC 3300
#define VREF_CAL_ADDR ((uint16_t*)((uint32_t) 0x1FFFF7BA))
#define cal_const_v_ref (uint16_t)*VREF_CAL_ADDR
пересчитанное напряжение питания AVDD
// 3300 is voltage of the factory calibration for STM32. Do not replace 3300 by VDDA_ADC.
vdda_adc = (3300*cal_const_v_ref )/adc_data_v_ref;
пересчитанное напряжение внутреннего источника
v_ref_int = (adc_data_v_ref * vdda_adc )/ADC_FULL_SCALE;
напряжение на входе батарейки
v_bat = (adc_data_v_bat * vdda_adc) /ADC_FULL_SCALE;