Перейти к содержанию
    

STM32F103C8T - перезапуск таймера от внешнего сигнала

Я с кубовым подхожу к окончанию проекта. Нареканий нет.

Нарекание уже хотя-бы то, что он монструозен, раздувает код до неприличных размеров.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Та мода, что вы описали есть в STM32F429. В описании (RM0090 Reference manual) глава 15.3.14 Timers and external trigger synchronization

Я не смотрел для вашего процессора. Может быть тоже есть.

 

Нарекание уже хотя-бы то, что он монструозен, раздувает код до неприличных размеров.

 

Мне пофиг пока хватает места.

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Ну что у вас? Получилось?

да, получилось. Картинка, как влитая. Ноги, правда, пришлось другие использовать.

Программа не особо чищена, но все работает. Нужна инициализация, дальше все прерывания делают. Буфера на страницу нет - слишком мало оперативки у процессора, только 20к. Изображение формируется "на лету", белое и черное.

#define FirstLine 30
#define LastLine 255
#define VIDEO_DELAY  820
#define VIDEO_EXRA_DELAY  400
//#define VIDEO_EXRA_DELAY  1000


uint16_t TestFlag=0x3333;
uint16_t LineCnt=0;
uint16_t LinePointer=0;
uint16_t Vsync_delay;

union buff_t
{
 uint16_t wData[26];
 uint8_t  bData[52];
};


buff_t WhiteBuffer1;
buff_t WhiteBuffer2;
buff_t BlackBuffer1;
buff_t BlackBuffer2;

void OSD_init(void)
{


 GPIO_InitTypeDef GPIO_InitStructure;
 NVIC_InitTypeDef NVIC_InitStructure;
 EXTI_InitTypeDef EXTI_InitStructure;
 TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
 TIM_OCInitTypeDef TIM_OCInitStructure;
 TIM_ICInitTypeDef TIM_ICInitStructure;
 SPI_InitTypeDef SPI_InitStructure;
 DMA_InitTypeDef DMA_InitStructure;


 for (int i=0; i<26; i++)
 {
  WhiteBuffer1.wData[i]= ~0x4040;
  BlackBuffer1.wData[i]= ~0x0004;

//     WhiteBuffer1[i]= ((i+1)<<8) +i +1;
//     BlackBuffer1[i]= ((i+1)<<8) +i +1;

  WhiteBuffer2.wData[i]= ~0x0040;
  BlackBuffer2.wData[i]= ~0x0404;
 }


 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);   // Enable GPIO Peripheral clock
 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
 RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);    // for Interrupt
 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);    // timer
 RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);    // SPI1
 RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE);
 RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);  // Enable DMA1 clock




 // Configure test pin in output push/pull mode
 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
 GPIO_Init(GPIOA, &GPIO_InitStructure);

 // ****************************************************
 // Vsync pin
 // ****************************************************
 // pin as input
 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
 GPIO_Init(GPIOA, &GPIO_InitStructure);
 // interrupt from Vsync
 NVIC_InitStructure.NVIC_IRQChannel = EXTI3_IRQn;
 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 5;
 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
 NVIC_Init(&NVIC_InitStructure);
 EXTI_ClearITPendingBit(EXTI_Line3);// Clear EXTI Line Pending Bit
 //  Connect EXTI
 GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource3);
 // Configure EXTI1 to generate an interrupt on falling edge
 EXTI_InitStructure.EXTI_Line = EXTI_Line3;
 EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
 EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
 EXTI_InitStructure.EXTI_LineCmd = ENABLE;
 EXTI_Init(&EXTI_InitStructure);

 // ****************************************************
 // Hsync timer
 // ****************************************************
 // pin as input
 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
 GPIO_Init(GPIOA, &GPIO_InitStructure);
 //
 TIM_TimeBaseStructure.TIM_Period = VIDEO_DELAY + VIDEO_EXRA_DELAY;
 TIM_TimeBaseStructure.TIM_Prescaler = 0;
 TIM_TimeBaseStructure.TIM_ClockDivision = 0;
 TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
 TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
 // TIM2 PWM2 Mode configuration: Channel1
 TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2;
 TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Disable;
 TIM_OCInitStructure.TIM_Pulse = VIDEO_DELAY;
 TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
 TIM_OC1Init(TIM2, &TIM_OCInitStructure);
 //
 TIM_ICInitStructure.TIM_Channel = TIM_Channel_2;
 TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;
 TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
 TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
 TIM_ICInitStructure.TIM_ICFilter = 0;
 TIM_ICInit(TIM2, &TIM_ICInitStructure);
 //
 TIM_SelectOnePulseMode(TIM2, TIM_OPMode_Single);
 TIM_SelectInputTrigger(TIM2, TIM_TS_TI2FP2);
 TIM_SelectSlaveMode(TIM2, TIM_SlaveMode_Trigger);
 //
 NVIC_EnableIRQ(TIM2_IRQn);

 // ****************************************************
 // SPI as black and white video
 // ****************************************************
 // SPI1 slave (black) PA6-MISO PA5-SCK
 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_6;
 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
 GPIO_Init(GPIOA, &GPIO_InitStructure);
 //
 SPI_InitStructure.SPI_Direction = SPI_Direction_1Line_Tx ;
 SPI_InitStructure.SPI_DataSize = SPI_DataSize_16b;
 SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;
 SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;
 SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
 SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_8;
 SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
 SPI_InitStructure.SPI_Mode = SPI_Mode_Slave;
 SPI_InitStructure.SPI_CRCPolynomial = 10;  // !!! mandatory!!!
 SPI_Init(SPI1, &SPI_InitStructure);
 // SPI2 master (white)  PB15-MISO PB13-SCK
 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_15;
 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
 GPIO_Init(GPIOB, &GPIO_InitStructure);
 //
 SPI_InitStructure.SPI_Direction = SPI_Direction_1Line_Tx ;
 SPI_InitStructure.SPI_DataSize = SPI_DataSize_16b;
 SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;
 SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;
 SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
 SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4;
 SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
 SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
 SPI_InitStructure.SPI_CRCPolynomial = 10;  // !!! mandatory!!!
 SPI_Init(SPI2, &SPI_InitStructure);
 //
 // ****************************************************
 // DMA
 // ****************************************************
 // Configure DMA1 - Channel5== (memory -> SPI)

 DMA_DeInit(DMA1_Channel3); //Set DMA registers to default values
 DMA_StructInit(&DMA_InitStructure);
 DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&SPI1->DR; //Address of peripheral the DMA must map to
 DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)BlackBuffer1.wData; //Variable from which data will be transmitted
 DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
 DMA_InitStructure.DMA_BufferSize = 26; //Buffer size
 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_Channel3, &DMA_InitStructure); //Initialize the DMA
 //
 // master SPI black
 DMA_DeInit(DMA1_Channel5); //Set DMA registers to default values
 DMA_StructInit(&DMA_InitStructure);
 DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&SPI2->DR; //Address of peripheral the DMA must map to
 DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)WhiteBuffer1.wData; //Variable from which data will be transmitted
 DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
 DMA_InitStructure.DMA_BufferSize = 26; //Buffer size
 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_Channel5, &DMA_InitStructure); //Initialize the DMA

 DMA_Cmd(DMA1_Channel3, ENABLE); // slave TX
 //
 //DMA_ITConfig(DMA1_Channel5, DMA_IT_TC, ENABLE);


 NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel5_IRQn;
 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 5;
 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
 NVIC_Init(&NVIC_InitStructure);

 NVIC_InitStructure.NVIC_IRQChannel = SPI1_IRQn;
 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 5;
 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
 NVIC_Init(&NVIC_InitStructure);



 // ****************************************************
 // enables
 // ****************************************************
 SPI1->CR2 |= 0x02;  // TX DMA Enable
 SPI2->CR2 |= 0x02;

}


// Vsync interrupt
extern "C" void EXTI3_IRQHandler(void)
{
 if(EXTI_GetITStatus(EXTI_Line3) != RESET)
 {
   EXTI_ClearITPendingBit(EXTI_Line3);
   if (Vsync_delay > 0)
   {
     if (--Vsync_delay==0)
     {
       SPI2->CR1 |= 0x0040;     // master SPI enable
       SPI1->CR1 |= 0x0040;     // slave SPI enable
       TIM2->DIER |= TIM_DIER_CC1IE | TIM_DIER_CC1DE; // Capture/Compare 1 DMA request and interrupt enable
       TIM2->CR1 |= 0x0001;   // enabled
     }
   }
   LineCnt=0;
   LinePointer=0;
 }
}


// Hsync interrupt
// master 5ch DMA SPI2
extern "C" void TIM2_IRQHandler(void)
{
 TIM2->SR &= ~TIM_IT_CC1;  // Clear CC1IF
 if ((LineCnt >  FirstLine) && (LineCnt <  LastLine))
 {
   TIM2->CR1 &= ~0x0001;   // timer disabled

   //GPIOA->ODR |= 0x04;

   TIM2->DIER &= ~TIM_DIER_CC1DE;   // DMA TIM disabled
SPI2->CR2 |= 0x02;             // DMA master enabled

   DMA1_Channel5->CCR |= DMA_CCR5_EN | DMA_CCR5_TCIE;    // enable DMA & int
   LinePointer++;
 }
 if (LineCnt == FirstLine)
 {
   DMA1_Channel5->CCR |= DMA_CCR5_EN | DMA_CCR5_TCIE;    // enable DMA & int
   DMA1_Channel3->CCR |= DMA_CCR3_EN;
 }
 LineCnt++;
}

// master DMA IRQ
extern "C" void DMA1_Channel5_IRQHandler(void)
//void DMA1_Channel5_IRQHandler(void)
{
 DMA1->IFCR = DMA_IFCR_CGIF5;  // clear int flag

 DMA1_Channel5->CCR &= ~(DMA_CCR5_EN | DMA_CCR5_TCIE);   // disable DMA & interrupt
 DMA1_Channel3->CCR &= ~DMA_CCR3_EN;

 SPI2->CR2 &= ~0x02;              // DMA master disabled
 SPI1->SR &= ~SPI_I2S_FLAG_TXE;   // Clear slane SPI TX INT
 SPI1->CR2 |= 0x80;               // slave SPI interrupt enable
}

// slave SPI IRQ
extern "C" void SPI1_IRQHandler(void)
{
 SPI1->SR &= ~SPI_I2S_FLAG_TXE;   // Clear SPI2 TX INT
 SPI1->CR2 &= ~0x80;  // SPI1  interrupt disable

 //GPIOA->ODR &= ~0x04;


 TIM2->SR &= ~ TIM_SR_CC1OF;   // compare flag
 TIM2->EGR &= ~ TIM_EGR_CC1G;  // capture/compare 1 generation
 TIM2->DIER |= TIM_DIER_CC1DE;   // DMA TIM enabled
 SPI2->CR2 &= ~0x02;             // DMA SPI1 disabled

 if (LineCnt != LastLine)
 {
   if(LineCnt & 0x01)
   {
     DMA1_Channel5->CMAR = (uint32_t)WhiteBuffer1.wData;
     DMA1_Channel3->CMAR = (uint32_t)BlackBuffer1.wData;
   }
   else
   {
     DMA1_Channel5->CMAR = (uint32_t)WhiteBuffer2.wData;
     DMA1_Channel3->CMAR = (uint32_t)BlackBuffer2.wData;
   }
   DMA1_Channel5->CCR |= DMA_CCR5_EN;    // enable DMA
   DMA1_Channel3->CCR |= DMA_CCR3_EN;
   flag |= 0x01;
 }
 else flag |= 0x02;
 TIM2->CR1 |= 0x0001;   // timer enabled

}

 

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

почему бы не использовать spi в режиме slave, дёргать nss строчным синхроимпульсом и заполнять через dma ?

минус таймер, плюс всё чисто аппаратно

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

почему бы не использовать spi в режиме slave, дёргать nss строчным синхроимпульсом и заполнять через dma ?

минус таймер, плюс всё чисто аппаратно

Так, собственно и так практически все аппаратно - прерывания только меняют режимы и переключают буфера.

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

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

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

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...