Ярлыки

_GetPixelIndex (1) _SetPixelIndex (1) 3-phase (1) 800x480 (1) АЦП (1) генератор (1) синхронный усилитель (2) структура (1) учебный курс (1) шаговый двигатель (1) ШИМ (2) accert (1) AD7608 (1) AD8429 (1) ADC (5) amplifer (1) arccos (1) arcsin (1) arctang (2) arctg (3) ARM (2) arm_sqrt_q15 (2) assembler (6) ASSERT (1) atan (2) bit (1) Bitband (1) boot (3) bootlloader (1) BUTTON (1) C (5) C# (1) CAN (2) CC2530 (5) CMSIS (4) command (1) Cordic (1) Core746I (1) CubeMX (4) DBGMCU (2) debug (2) debug.ini (1) delegate (1) Digital Potentiometers (1) DigitalPOT (1) Discovery (1) DMA (9) DMA2D (1) DSP (1) DSP library (1) DWT (1) EFM32 (5) EmWin (9) EXTI (1) FATFS (1) FMC (2) FreeRTOS (2) gl868-dual cmux (1) GPIO (4) GUI (2) GUIBuilder (1) GUIDRV_CompactColor_16 (1) HAL (3) HappyGecko (1) Hard Fault (2) heap (1) I2C (1) ID (1) ILI9320 (1) ILI9325 (1) Initialisation (1) InitLTDC (1) Instrumentithion (1) Interrupt (4) ITR (1) JTAG (1) Keil (5) LCDConf (2) lock-in (1) LTCD (1) LTDC (3) main (1) memory (1) MINI_STM32 Revision 01 (1) nBoot0 (1) NVIC (1) OnePulse (2) OSAL (4) pack (1) phase (1) printf (3) Pulse (1) PWM (12) RCC (2) RCR (1) Register (1) RESET (2) RS232 (3) RSS (1) RTC (3) RTOS-RTX (1) RTT (1) RTX-RTOS (1) SDCard (1) SDRAM (6) Segger (2) SPI (3) sqrt (3) SSD1298 (1) SSD1963 (1) Standart Peripherial Library (3) STANDBAY (1) startup (1) STemWin (8) stepper motor (1) STlink (2) STM32 (17) STM32429ZI (1) STM32Cube (1) STM32DBG.IN (1) STM32F (28) STM32F0 (4) STM32F1 (13) STM32F4 (10) STM32F4 Discovery (1) STM32F407ZG (1) STM32F429 (2) STM32F746 (1) STOP (1) string (1) struct (1) SWD (1) SWD JTAG (1) Synhronization (1) system_stm32f4xx.c (1) SystemInit (1) SysTick (1) task (4) telit (1) TIM (27) typedef (1) UART (1) USART (9) viewer (2) WM_PAINT (1) Z-stack (5) ZigBee (5)
Показаны сообщения с ярлыком STM32F1. Показать все сообщения
Показаны сообщения с ярлыком STM32F1. Показать все сообщения

суббота, 23 мая 2015 г.

2-х фазный ШИМ генератор 400 Герц на STM32F103

2-х фазный ШИМ генератор 400 Герц на STM32F103 с фазами, сдвинутыми на 90 градусов. Частота ШИМ генерации 40 кГц. Для генерации используется TIM4.


понедельник, 16 февраля 2015 г.

RCC STM32F1

Контроллеры STM32 обладают достаточно развитой системой тактирования, включающей кучу различных делителей, умножителей и селекторов, которые позволяют "разогнать" до 72 МГц частоту ядра и системной шины, а также организовать тактирование на различных частотах всех входящих в состав контроллера модулей (USB, I/O, I2C, SPI...).

При этом стартует контроллер всегда от внутреннего генератора на 8 МГц, а дальнейший "разгон" и настройка тактирования различных модулей выполняется программно.

Все регистры, отвечающие за настройку системы тактирования сгруппированы в так называемый блок RCC (reset and clock control). Это десять 32-х битных регистров, доступных в памяти начиная с адреса 0x40021000, названия которых начинаются с "RCC_".

Настройку системы тактирования можно разделить на два этапа. На первом этапе настраивается системная тактовая частота. На втором этапе - частота системной шины AHB и подключенные к шине AHB модули. Отдельно от этих двух этапов можно настроить низкоскоростные генераторы для часов реального времени и независимого "собачьего таймера".

среда, 17 декабря 2014 г.

STM32F103 PWM init TIM1

  

  RCC->APB2ENR |= RCC_APB2ENR_IOPBEN;       // Enable GPIOB clocking  RCC->APB2ENR |= RCC_APB2ENR_IOPAEN;       // Enable GPIOA clocking  RCC->APB2ENR |= RCC_APB2ENR_TIM1EN;       // Enable TIM1 clocking  RCC->APB2ENR |= RCC_APB2ENR_AFIOEN;       // Enable AFIO clocking  //////////////////////////////////////////////////////////////////////////////// GPIO  GPIOB->CRL  = (GPIO_CRL_MODE0 | 
                 GPIO_CRL_CNF0_1
);    // PB0 - Output mode 50 MHz   GPIOB->CRL &= (~GPIO_CRL_CNF0_0);   // and alternate push-pull  //----------------------------------------  GPIOA->CRL |= (GPIO_CRL_MODE7 | GPIO_CRL_CNF7_1); // PA7 - Output mode 50 MHz   GPIOA->CRL &= (~GPIO_CRL_CNF7_0); // and alternate push-pull  //----------------------------------------  GPIOA->CRH |= (GPIO_CRH_MODE8 | 
                 GPIO_CRH_MODE9 
| 
                 GPIO_CRH_CNF8_1 
| 
                 GPIO_CRH_CNF9_1
); // PA8, PA9 - Output mode 50 MHz  GPIOA->CRH &= (~(GPIO_CRH_CNF8_0 | 
                   GPIO_CRH_CNF9_0
)); // and alternate push-pull  GPIOA->ODR = 0x0000;//---------------------------------------
  
AFIO->MAPR |= AFIO_MAPR_TIM1_REMAP_0;
  
AFIO->MAPR &= (~AFIO_MAPR_TIM1_REMAP_1);  //////////////////////////////////////////////////////////////////////////////// PWM Timer 1  TIM1->CR1 = TIM_CR1_ARPE;  TIM1->PSC = 8;  TIM1->ARR = 0x00FF;  
  TIM1
->CCR1 = 100;  TIM1->CCR2 = 0xFF;  TIM1->CCR3 = 0x00;  TIM1->CCR4 = 0x00;  
  TIM1
->CCMR1 = (TIM_CCMR1_OC1PE | TIM_CCMR1_OC1M |                 TIM_CCMR1_OC2PE | TIM_CCMR1_OC2M);  
  TIM1
->CCER = (TIM_CCER_CC1E | /*TIM_CCER_CC1P |*/                TIM_CCER_CC1NE | /*TIM_CCER_CC1NP |*/                TIM_CCER_CC2E | /*TIM_CCER_CC2P |*/                TIM_CCER_CC2NE /*| TIM_CCER_CC2NP*/);  
  TIM1
->BDTR = (TIM_BDTR_MOE | ((4<<5) | 10));  
  TIM1
->CR1 |= TIM_CR1_CEN;



#include "stm32f10x_lib.h"   
#include "pwm.h"   
   
TIM1_TimeBaseInitTypeDef  TIM1_TimeBaseStructure;   
TIM1_OCInitTypeDef  TIM1_OCInitStructure;   
TIM1_BDTRInitTypeDef TIM1_BDTRInitStructure;   
extern GPIO_InitTypeDef GPIO_InitStructure;   
   
void InitPWM(void) {   
   
  // Enable GPIOA and GPIOB clock   
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);   
   
  // GPIOA Configuration: Channel 1   
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;   
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;   
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;   
  GPIO_Init(GPIOA, &GPIO_InitStructure);   
   
  // Enable TIM1 clock   
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);   
   
  // TIM1 Peripheral Configuration   
  TIM1_DeInit();   
   
  // Time Base configuration   
  TIM1_TimeBaseStructure.TIM1_Prescaler = 0x0;   
  TIM1_TimeBaseStructure.TIM1_CounterMode = TIM1_CounterMode_Up;   
  // TIM1_TimeBaseStructure.TIM1_Period = 0xFFF; // 12 bit   
  TIM1_TimeBaseStructure.TIM1_Period = 0x3FF; // 10 bit   
  TIM1_TimeBaseStructure.TIM1_ClockDivision = 0x0;   
  TIM1_TimeBaseStructure.TIM1_RepetitionCounter = 0x0;   
  TIM1_TimeBaseInit(&TIM1_TimeBaseStructure);   
   
   
  // Channel 1 Configuration in PWM mode   
  TIM1_OCInitStructure.TIM1_OCMode = TIM1_OCMode_PWM2;   
  TIM1_OCInitStructure.TIM1_OutputState = TIM1_OutputState_Enable;   
  TIM1_OCInitStructure.TIM1_OutputNState = TIM1_OutputNState_Enable;   
  TIM1_OCInitStructure.TIM1_Pulse = 0x3FF;   
  TIM1_OCInitStructure.TIM1_OCPolarity = TIM1_OCPolarity_Low;   
  TIM1_OCInitStructure.TIM1_OCNPolarity = TIM1_OCNPolarity_Low;   
  TIM1_OCInitStructure.TIM1_OCIdleState = TIM1_OCIdleState_Set;   
  TIM1_OCInitStructure.TIM1_OCNIdleState = TIM1_OCIdleState_Reset;   
  TIM1_OC1Init(&TIM1_OCInitStructure);   
   
  // Automatic Output enable, Break, dead time and lock configuration   
  TIM1_BDTRInitStructure.TIM1_OSSRState = TIM1_OSSRState_Enable;   
  TIM1_BDTRInitStructure.TIM1_OSSIState = TIM1_OSSIState_Enable;   
  TIM1_BDTRInitStructure.TIM1_LOCKLevel = TIM1_LOCKLevel_1;   
  TIM1_BDTRInitStructure.TIM1_DeadTime = 0x05;   
  TIM1_BDTRInitStructure.TIM1_Break = TIM1_Break_Disable;   
  TIM1_BDTRInitStructure.TIM1_BreakPolarity = TIM1_BreakPolarity_High;   
  TIM1_BDTRInitStructure.TIM1_AutomaticOutput = TIM1_AutomaticOutput_Enable;   
  TIM1_BDTRConfig(&TIM1_BDTRInitStructure);   
   
  // TIM1 counter enable   
  TIM1_Cmd(ENABLE);   
   
  // Main Output Enable   
  TIM1_CtrlPWMOutputs(ENABLE);   
   
}   
   
void SetDutyPeriod(Int16U period) {   
   
  TIM1_OCInitStructure.TIM1_Pulse = period;   
  TIM1_OC1Init(&TIM1_OCInitStructure);   
   
}   

   

воскресенье, 14 декабря 2014 г.

General-purpose timers (TIM2 to TIM5) RM0008


Все блоки таймеров выполнены на основе 16-битного перезагружаемого счетчика, который синхронизируется с выхода 16-битного предделителя. Перезагружаемое значение хранится в отдельном регистре. Счет может быть прямой, обратный или двунаправленный (сначала прямой до определенного значения, а затем обратный). Вход синхронизации счетчика можно связать с одним из восьми различных источников. В их число входят: специальный сигнал синхронизации, производный от сигнала главной системной синхронизации; выходной сигнал синхронизации одного из других таймеров или внешний сигнал синхронизации, связанный с выводами захвата/сравнения.


Каждый из четырех таймеров МК STM32 содержит 16-битный счетчик, 16-битный предделитель частоты и 4-канальный блок захвата/сравнения. Их можно синхронизировать системной синхронизацией, внешними сигналами или другими таймерами. 
Помимо составляющего основу таймера счетчика, в каждый блок таймера также входит четырехканальный блок захвата/сравнения. Данный блок выполняет, как стандартные функции захвата и сравнения, так и ряд специальных функций. Каждый из таймеров может генерировать прерывания и поддерживает ПДП. Каждый канал захвата/сравнения управляется через один регистр. Данный регистр имеет несколько функций, которые зависят от установок бит выбора. В режиме захвата, данный блок выполняет фильтрацию на входах, поддерживает специальный режим измерения внешнего ШИМ-сигнала, а также имеет входы для подключения внешнего энкодера. В режиме сравнения, блок выполняет стандартные функции сравнения, генерации ШИМ-сигналов, а также поддерживает опциональную функцию одновибратора.

Basic таймеры тактируются от шины APB1. Если ничего не менять в настройках тактирования и оставить их по умолчанию, то частота APB1 составляет 72МГц при условии что подключен внешний кварц на частоту 8 МГц. 
TIMx_CNT-счётный 16-ти битный регистр, занимающийся непосредственно счётом времени. Каждый раз когда с шины APB1 приходит тактовый импульс, содержимое этого регистра увеличивается на едницу. Когда регистр переполняется, все начинается с нуля. При дефолтной частоте шины APB1, таймер за одну секунду тикнет 72 млн раз! Это очень дофига, и поэтому у таймера есть предделитель, управлять которым мы можем при помощи регистра TIMx_PSC. Записав в него значение 72000-1 мы заставим счётный регистр TIMx_CNT увеличивать свое значение каждую милисекунду (Частоту APB1 делим на число в регистре предделителе и получаем сколько раз в секунду увеличивается счётчик). Единицу нужно вычесть потому, что если в регистре ноль то это означает, что включен делитель на единицу. Теперь, когда счётный регистр дотикает до 1000 мы можем точно заявить, что прошла ровно одна секунда! И че теперь опрашивать счётный регистр и ждать пока там появится 1000? Это не наш метод, ведь мы можем заюзать прерывания! Но вот беда, прерывание у нас всего одно, и возникает оно когда счётчик обнулится. Для того чтоб счётчик обнулялся досрочно, а не когда дотикает до 0xFFFF, служит регистр TIMx_ARR. Записываем в него то число до которого должен досчитывать регистр TIMx_CNT перед тем как обнулиться. Если мы хотим чтоб прерывание возникало раз в секунду, то нам нужно записать туда 1000. По части непосредственно отсчёта времени это все, но таймер сам по себе тикать не начнет. Его нужно включить установив бит CEN в регистре TIMx_CR1. Этот бит разрешает начать отсчёт, соответственно если его сбросить то отсчет остановится (ваш К.О.). В регистре есть и другие биты но они нам не особо интересны. Зато интересен нам еще один бит, но уже в регистре TIMx_DIER. Называется он UIE, установив его мы разрешаем таймеру генерить прерывания при сбросе счётного регистра.  Итак небольше резюме: Чтоб заюзать basic таймер нужно:

-Установить предделитель чтоб таймер не тикал быстро (TIMx_PSC)
-Задать предел до которого таймер должен дотикать перед своим сбросом (TIMx_ARR)
-Включить отсчет битом CEN в регистре TIMx_CR1 
-Включить прерывание по переполнению битом UIE в регистре TIMx_DIER


суббота, 29 ноября 2014 г.

SPI2 в режиме мастера для работы с DMA

void SPI_init(void)
{
// SPI2 init
        RCC->APB1ENR |= RCC_APB1ENR_SPI2EN; // такты на SPI2

        GPIOB->CRH &= (~(GPIO_CRH_CNF13_0 | GPIO_CRH_CNF15_0)); //настройка выводов для SPI
        GPIOB->CRH |= (GPIO_CRH_MODE13 | GPIO_CRH_MODE15                
         | GPIO_CRH_CNF13_1 | GPIO_CRH_CNF15_1);                // AF Push-Pull out

        SPI2->CR1 |= SPI_CR1_BR_1    //настройка делителя 
//       | SPI_CR1_BR_0    //комментируя или раскомментируя эти строки можно изменять значение делителя 
//       | SPI_CR1_BR_2
         | SPI_CR1_SSM   // программное управление слэйвом
         | SPI_CR1_SSI   // при программном управлении слэйвом данный бит должен быть 1
         | SPI_CR1_MSTR  // Режим мастера
         | SPI_CR1_SPE;   // разрешить SPI2 

        SPI2->CR2 |= SPI_CR2_RXDMAEN // разрешить передачу принятых данных через DMA
         | SPI_CR2_TXDMAEN; // Разрешить принимать данные для передачи через DMA

        return;
}

DMA для работы с SPI2 на прием и передачу



        RCC->AHBENR |= RCC_AHBENR_DMA1EN; //такты

        // 4 канал DMA1  RX SPI2 -> память
        DMA1_Channel4->CPAR = SPI2_BASE+0x0C; // адрес DR
        DMA1_Channel4->CMAR = pSPI2_readbuf_addr->Buf_Addr; //адрес буфера приема
        DMA1_Channel4->CNDTR = 12; // размер транзакции
        DMA1_Channel4->CCR |= DMA_CCR4_MINC     //инкремент адреса буфера
        | DMA_CCR4_PSIZE_0;     //размерность данных SPI 16 бит (происходит автоматическое преобразование 16->8 бит)

        // 5 канал DMA1  память -> TX SPI2
        DMA1_Channel5->CPAR = SPI2_BASE+0x0C; //адрес DR
        DMA1_Channel5->CMAR = pSPI2_writebuf_addr->Buf_Addr; //адрес буфера передачи
        DMA1_Channel5->CNDTR = 12; // размер транзакции
        DMA1_Channel5->CCR |= DMA_CCR5_MINC     //инкремент адреса буфера
        | DMA_CCR5_DIR; // направление передачи из памяти в периферию


Транзакция запускается следующим куском кода:


void SPI2_start (void) // По сути это переинициализация каналов DMA
{
        DMA1_Channel4->CPAR = SPI2_BASE+0x0C; //DR Base 
        DMA1_Channel4->CMAR = pSPI2_readbuf_addr->Buf_Addr;
        DMA1_Channel4->CNDTR = 12;
        DMA1_Channel5->CPAR = SPI2_BASE+0x0C; //DR Base
        DMA1_Channel5->CMAR = pSPI2_writebuf_addr->Buf_Addr;
        DMA1_Channel5->CNDTR = 12;
        DMA1_Channel4->CCR |= DMA_CCR4_TCIE | DMA_CCR4_EN;
        DMA1_Channel5->CCR |= DMA_CCR5_EN;
        return;
}


Результаты обрабатываются по прерыванию завершения работы канала DMA работающего на прием данных от SPI:


void DMAChannel4_IRQHandler     (void)
{
        DMA1_Channel4->CCR &= (~(DMA_CCR4_TCIE | DMA_CCR4_EN)); // выключаем канал приемника и его прерывание
        DMA1->IFCR |= DMA_IFCR_CTCIF4 | DMA_IFCR_CGIF4; //очищаем флаги
        DMA1_Channel5->CCR &= (~(DMA_CCR5_EN)); // выключаем канал передатчика
        pCurrent_mode->stat.led_data_send = 0; // выставляем нужные флаги для дальнейшей работы с данными 
        HC595_OUT;
        pCurrent_mode->stat.read_key_data_ready=1;
        return;
}