Advertisement
Guest User

dimmer.c

a guest
Jan 20th, 2013
7,336
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 6.68 KB | None | 0 0
  1. /* AC dimmer control */
  2. #include <stdint.h>
  3. #include <stdbool.h>
  4.  
  5. #include "stm32f10x.h"
  6.  
  7. #include "FreeRTOS.h"
  8. #include "task.h"
  9. #include "queue.h"
  10. #include "semphr.h"
  11.  
  12. /*-----------------------------------------------------------------------------*/
  13. /*
  14. Timer chain:
  15. TIM1 -> (ITR0) TIM4 -> (ITR3) TIM2
  16. */
  17. /*-----------------------------------------------------------------------------*/
  18. /* Use TIM1_CH1 (PA8) */
  19. #define ZC_GPIO GPIOA
  20. #define ZC_PIN GPIO_Pin_8
  21. #define ZC_CLK_ENABLE \
  22.     RCC_APB2PeriphClockCmd((RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO | RCC_APB2Periph_TIM1), ENABLE)
  23. #define ZC_TIMER TIM1 /* Uses APB2 clock */
  24. #define ZC_TIMER_CHANNEL TIM_Channel_1
  25. #define ZC_IRQN TIM1_CC_IRQn
  26. #define ZC_IRQ_HANDLER TIM1_CC_IRQHandler
  27. #define ZC_GET_PCLK_FREQ(x) (((RCC->CFGR >> 11) & 0x7) >= 4 ? (x)->PCLK2_Frequency * 2 : (x)->PCLK2_Frequency)
  28. #define ZC_IRQ_PRIO (configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY + 1)
  29.  
  30. /*-----------------------------------------------------------------------------*/
  31. /* Use TIM4 for phase control */
  32. #define PHASE_CLK_ENABLE RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE)
  33. #define PHASE_TIMER TIM4 /* Uses APB1 clock */
  34. #define PHASE_GET_PCLK_FREQ(x) (((RCC->CFGR >> 8) & 0x7) >= 4 ? (x)->PCLK1_Frequency * 2 : (x)->PCLK1_Frequency)
  35. #define PHASE_TRIGGER TIM_TS_ITR0 /* <- TIM1 */
  36.  
  37. /*-----------------------------------------------------------------------------*/
  38. /* Use TIM2_CH4 (remapped to PA0) for PWM */
  39. #define PWM_GPIO GPIOA
  40. #define PWM_PIN GPIO_Pin_0
  41. #define PWM_CLK_ENABLE \
  42. do { \
  43.     RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); \
  44.     RCC_APB2PeriphClockCmd((RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO), ENABLE); \
  45. } while(0)
  46. #define PWM_TIMER TIM2 /* Uses APB1 clock */
  47. #define PWM_TIMER_CHANNEL_INIT(x) TIM_OC1Init(PWM_TIMER, (x))
  48. #define PWM_TIMER_CHANNEL_REG CCR1
  49. #define PWM_GET_PCLK_FREQ(x) (((RCC->CFGR >> 8) & 0x7) >= 4 ? (x)->PCLK1_Frequency * 2 : (x)->PCLK1_Frequency)
  50. #define PWM_TRIGGER TIM_TS_ITR3 /* <- TIM4 */
  51.  
  52. #define BASE_FREQ 1000000
  53. #define MAX_VALUE 100
  54. #define TRIAC_TRIGGER_PULSE_US 100
  55.  
  56. /*-----------------------------------------------------------------------------*/
  57. static volatile unsigned int dimmer_phase = 0;
  58.  
  59. static const uint16_t acostab[MAX_VALUE - 1] = {
  60.     959, 931, 911, 893, 877, 863, 849, 837, 825, 814, 804, 793, 784, 774,
  61.     765, 756, 747, 738, 730, 722, 714, 706, 698, 690, 683, 675, 668, 661, 653, 646,
  62.     639, 632, 625, 618, 611, 605, 598, 591, 584, 578, 571, 564, 558, 551, 545, 538,
  63.     532, 525, 519, 512, 505, 499, 492, 486, 479, 473, 466, 460, 453, 446, 440, 433,
  64.     426, 419, 413, 406, 399, 392, 385, 378, 371, 363, 356, 349, 341, 334, 326, 318,
  65.     310, 302, 294, 286, 277, 268, 259, 250, 240, 231, 220, 210, 199, 187, 175, 161,
  66.     147, 131, 113, 93, 65
  67. };
  68. /*-----------------------------------------------------------------------------*/
  69. void dimmer_init() {
  70.     /* Enable clocks */
  71.     ZC_CLK_ENABLE;
  72.     PHASE_CLK_ENABLE;
  73.     PWM_CLK_ENABLE;
  74.  
  75.     /* Pin configuration */
  76.     GPIO_InitTypeDef gpconf = {
  77.         .GPIO_Pin = ZC_PIN,
  78.         .GPIO_Mode = GPIO_Mode_IN_FLOATING,
  79.         .GPIO_Speed = GPIO_Speed_50MHz,
  80.     };
  81.     GPIO_Init(ZC_GPIO, &gpconf);
  82. #ifdef ZC_GPIO_REMAP
  83.     GPIO_PinRemapConfig(ZC_GPIO_REMAP, ENABLE);
  84. #endif
  85.  
  86.     gpconf.GPIO_Pin = PWM_PIN;
  87.     gpconf.GPIO_Mode = GPIO_Mode_AF_PP;
  88.     GPIO_Init(PWM_GPIO, &gpconf);
  89. #ifdef PWM_GPIO_REMAP
  90.     GPIO_PinRemapConfig(PWM_GPIO_REMAP, ENABLE);
  91. #endif
  92.  
  93.     /* Enable the TIM global Interrupt */
  94.     NVIC_InitTypeDef itconf = {
  95.         .NVIC_IRQChannel = ZC_IRQN,
  96.         .NVIC_IRQChannelPreemptionPriority = ZC_IRQ_PRIO,
  97.         .NVIC_IRQChannelSubPriority = 0,
  98.         .NVIC_IRQChannelCmd = ENABLE,
  99.     };
  100.     NVIC_Init(&itconf);
  101.  
  102.     /* PWM capture configuration */
  103.     /* Give 1us resolution */
  104.     RCC_ClocksTypeDef clocks;
  105.     RCC_GetClocksFreq(&clocks);
  106.     unsigned long freq = ZC_GET_PCLK_FREQ(&clocks);
  107.     TIM_PrescalerConfig(ZC_TIMER, freq / BASE_FREQ - 1, TIM_PSCReloadMode_Immediate);
  108.  
  109.     TIM_ICInitTypeDef icconf = {
  110.         .TIM_Channel = ZC_TIMER_CHANNEL,
  111.         .TIM_ICPolarity = TIM_ICPolarity_Rising,
  112.         .TIM_ICSelection = TIM_ICSelection_DirectTI,
  113.         .TIM_ICPrescaler = TIM_ICPSC_DIV1,
  114.         .TIM_ICFilter = 0x7,
  115.     };
  116.     TIM_PWMIConfig(ZC_TIMER, &icconf);
  117.  
  118.     TIM_SelectInputTrigger(ZC_TIMER, TIM_TS_TI1FP1); /* Select the Input Trigger: TI1FP1 */
  119.     TIM_SelectOutputTrigger(ZC_TIMER, TIM_TRGOSource_Reset);
  120.     TIM_SelectSlaveMode(ZC_TIMER, TIM_SlaveMode_Reset); /* Select the slave Mode: Reset Mode */
  121.     TIM_SelectMasterSlaveMode(ZC_TIMER, TIM_MasterSlaveMode_Enable); /* Enable the Master/Slave Mode */
  122.  
  123.     ZC_TIMER->CNT = 0;
  124.     ZC_TIMER->ARR = 0xffff;
  125.  
  126.     /* Setup phase timer */
  127.     freq = PHASE_GET_PCLK_FREQ(&clocks);
  128.     TIM_PrescalerConfig(PHASE_TIMER, freq / BASE_FREQ - 1, TIM_PSCReloadMode_Immediate);
  129.     TIM_SelectInputTrigger(PHASE_TIMER, PHASE_TRIGGER); /* connect to capture timer */
  130.     TIM_SelectOutputTrigger(PHASE_TIMER, TIM_TRGOSource_Update);
  131.     TIM_SelectSlaveMode(PHASE_TIMER, TIM_SlaveMode_Trigger);
  132.     TIM_SelectMasterSlaveMode(PHASE_TIMER, TIM_MasterSlaveMode_Enable);
  133.     TIM_SelectOnePulseMode(PHASE_TIMER, TIM_OPMode_Single);
  134.  
  135.     PHASE_TIMER->CNT = 0;
  136.     PHASE_TIMER->ARR = 0;
  137.  
  138.     /* Setup PWM output */
  139.     /* Give 1us resolution */
  140.     freq = PWM_GET_PCLK_FREQ(&clocks);
  141.     TIM_PrescalerConfig(PWM_TIMER, freq / BASE_FREQ - 1, TIM_PSCReloadMode_Immediate);
  142.  
  143.     /* PWM1 Mode configuration: Channel1 */
  144.     TIM_OCInitTypeDef occonf = {
  145.         .TIM_OCMode = TIM_OCMode_PWM1,
  146.         .TIM_OutputState = TIM_OutputState_Enable,
  147.         .TIM_Pulse = 0, /* disabled initially */
  148.         .TIM_OCPolarity = TIM_OCPolarity_High,
  149.     };
  150.     PWM_TIMER_CHANNEL_INIT(&occonf);
  151.  
  152.     TIM_SelectInputTrigger(PWM_TIMER, PWM_TRIGGER); /* connect to phase timer */
  153.     TIM_SelectSlaveMode(PWM_TIMER, TIM_SlaveMode_Reset); /* Select the slave Mode: Reset Mode */
  154.     TIM_SelectMasterSlaveMode(PWM_TIMER, TIM_MasterSlaveMode_Enable); /* Enable the Master/Slave Mode */
  155.  
  156.     PWM_TIMER->CNT = 0;
  157.     PWM_TIMER->ARR = 0xffff; /* initial value */
  158.  
  159.     /* Start ZC timer */
  160.     ZC_TIMER->DIER |= TIM_IT_CC1;
  161.     ZC_TIMER->SR = ~TIM_FLAG_CC1;
  162.     ZC_TIMER->CR1 |= TIM_CR1_CEN;
  163.  
  164.     /* Start PWM timer */
  165.     PWM_TIMER->CR1 |= TIM_CR1_CEN;
  166. }
  167.  
  168. void dimmer_set(unsigned int val) {
  169.     if(val >= MAX_VALUE) {
  170.         /* always on */
  171.         PWM_TIMER->PWM_TIMER_CHANNEL_REG = 0xffff;
  172.     } else if(!val) {
  173.         /* always off */
  174.         PWM_TIMER->PWM_TIMER_CHANNEL_REG = 0;
  175.     } else {
  176.         PWM_TIMER->PWM_TIMER_CHANNEL_REG = TRIAC_TRIGGER_PULSE_US;
  177.         dimmer_phase = acostab[val - 1];
  178.     }
  179. }
  180.  
  181. /*-----------------------------------------------------------------------------*/
  182. void ZC_IRQ_HANDLER(void) {
  183.     if(ZC_TIMER->SR & TIM_FLAG_CC1) {
  184.         unsigned int half = ZC_TIMER->CCR1 >> 1;
  185.         PWM_TIMER->ARR = half - 1; /* correct period */
  186.         PHASE_TIMER->ARR = ((ZC_TIMER->CCR2 - half) >> 1) + ((dimmer_phase * half) >> 10);
  187.  
  188.         ZC_TIMER->SR = ~TIM_FLAG_CC1;
  189.     }
  190. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement