コード例 #1
0
ファイル: cog.c プロジェクト: AndreMiras/EFM32-Library
/**********************************************************
 * COG power-up sequence. 
 **********************************************************/
void cogPowerUp(void)
{
  measureTemperature();
  
  GPIO_PinOutSet(EPD_PIN_PANEL_VDD);
  
  delayMs(5);
  
  pwmEnable();
  
  delayMs(5);
  
  GPIO_PinOutSet(EPD_PIN_PANEL_ON);
  
  delayMs(10);
  
  GPIO_PinOutSet(EPD_PIN_CS);
  
  GPIO_PinOutSet(EPD_PIN_BORDER);
  
  GPIO_PinOutSet(EPD_PIN_RESET);
  
  delayMs(5);
  
  GPIO_PinOutClear(EPD_PIN_RESET);
  
  delayMs(5);
  
  GPIO_PinOutSet(EPD_PIN_RESET);
  
  delayMs(5);
}
コード例 #2
0
ファイル: main.c プロジェクト: stxent/halm-examples
/*----------------------------------------------------------------------------*/
int main(void)
{
  const uint32_t maxPeriod =
      captureUnitConfig.frequency / pwmUnitConfig.frequency + 1;
  const uint32_t minPeriod =
      captureUnitConfig.frequency / pwmUnitConfig.frequency - 1;

  setupClock();

  const struct Pin led = pinInit(LED_PIN);
  pinOutput(led, false);

  struct GpTimerPwmUnit * const pwmUnit = init(GpTimerPwmUnit,
      &pwmUnitConfig);
  assert(pwmUnit);

  struct Pwm * const pwm = gpTimerPwmCreate(pwmUnit, OUTPUT_PIN);
  assert(pwm);
  pwmSetEdges(pwm, 0, pwmGetResolution(pwm) / 2);

  struct GpTimerCaptureUnit * const captureUnit = init(GpTimerCaptureUnit,
      &captureUnitConfig);
  assert(pwmUnit);

  struct Capture * const capture = gpTimerCaptureCreate(captureUnit, INPUT_PIN,
      PIN_RISING, PIN_PULLDOWN);
  assert(capture);

  uint32_t previousTime = 0;
  bool event = false;

  captureSetCallback(capture, onCaptureEvent, &event);
  captureEnable(capture);
  pwmEnable(pwm);

  while (1)
  {
    while (!event)
      barrier();
    event = false;

    const uint32_t currentTime = captureGetValue(capture);
    const uint32_t period = currentTime - previousTime;

    if (period >= minPeriod && period <= maxPeriod)
      pinReset(led);
    else
      pinSet(led);

    previousTime = currentTime;
  }

  return 0;
}
コード例 #3
0
ファイル: main.c プロジェクト: stxent/halm-examples
/*----------------------------------------------------------------------------*/
int main(void)
{
  setupClock();

  const struct Pin led = pinInit(LED_PIN);
  pinOutput(led, true);

  struct GpTimerPwmUnit * const pwmUnit = init(GpTimerPwmUnit, &pwmUnitConfig);
  assert(pwmUnit);
  struct Pwm * const pwmOutput = gpTimerPwmCreate(pwmUnit, OUTPUT_PIN);
  assert(pwmOutput);
  pwmSetDuration(pwmOutput, pwmGetResolution(pwmOutput) / 2);

  struct Timer * const counter = init(GpTimerCounter, &counterConfig);
  assert(counter);

  struct Timer * const timer = init(GpTimer, &timerConfig);
  assert(timer);
  timerSetOverflow(timer, 1000);

  bool event = false;
  timerSetCallback(timer, onTimerOverflow, &event);

  timerEnable(counter);
  pwmEnable(pwmOutput);
  timerEnable(timer);

  while (1)
  {
    while (!event)
      barrier();
    event = false;

    const uint32_t period = timerGetValue(counter);
    timerSetValue(counter, 0);

    if (period >= 999 && period <= 1001)
      pinReset(led);
    else
      pinSet(led);
  }

  return 0;
}
コード例 #4
0
/*
 * Parameter time: Aktuelle Zeit, kann systemTime sein
 *                 Es bietet sich an eine Zeit im ms Raster zu benutzen, dies muss jedoch nicht sein.
 *                 So könnte die Zeit genauso das Timerraster widerspiegeln, in dem die Routine aufgerufen
 *                 wird. Dann müssen die Konstanten für die Wartezeiten natürlich ebenfalls nach dieser Einheit
 *                 ausgerichtet sein.
 * Es gibt eine Wartezeit direkt nach einer Bestromung der Relaisspule. Sie dient dazu, besser den
 * Ladezustand der Bulkkondensatoren ermitteln zu können. Daraus wird die Anzahl der anschließend möglichen
 * Schaltvorgänge ermittelt.
 * Rückgabewert true wenn neue SPI-Daten generiert wurden, also eine Übertragung notwendig wäre.
 */
bool Relay::DoSwitching(unsigned time, unsigned &RelDriverData)
{
 bool retval = false;
 IdleDetect(time);
 // Erst die Verwaltung der SubStates (aktuell laufender Puls, Wartezeit nach Puls...)
 // =================================
 if (SubState == RelSubStates::Pulse) // Es wird gerade eine/mehrere Relaisspulen bestromt
 {
#ifdef RELAYUSEDISCRETETIMING
  if ((signed)(time-NextPointInTime) >= 0)
  //if ((time-PulseStartTime) >= RELAYPULSEDURATION)
#else
  if ((signed)(time-NextPointInTime) > 0)
  //if ((time-PulseStartTime) > RELAYPULSEDURATION)
#endif
  {
   DriverData = 0;
   retval = true;
   SubState = RelSubStates::Delay;
   NextPointInTime = time + RELAYPOSTDELAY1;
  }
 }

 if (SubState == RelSubStates::Delay) // Wartezeit nach einem Ansteuerpuls für eine korrekte Vermessung
 {
#ifdef RELAYUSEDISCRETETIMING
  if ((signed)(time-NextPointInTime) >= 0)
  //if ((time-PulseStartTime) >= RELAYPOSTDELAY)
#else
  if ((signed)(time-NextPointInTime) > 0)
  //if ((time-PulseStartTime) > RELAYPOSTDELAY)
#endif
  {
   pwmEnable(false);

   SubState = RelSubStates::Delay2;
   NextPointInTime = time + RELAYPOSTDELAY2;
   if (OpState == RelOperatingStates::MeasMode)
   {
    unsigned zw1 = EnergyCalcRefVoltage;
    zw1 = zw1*zw1;
    // aktuelle Bulkspannung festhalten
    unsigned zw2 = GetRailVoltage();
    zw2 = zw2*zw2;
    if (zw1 > zw2)
    {
     // Benötigte Energie ausrechnen und abspeichern
     SingleSwitchEnergy = zw1 - zw2; // Nach Messungen keine Sicherheitsmarge erforderlich
    } else {
     // Problem... Einfach eine seeehr große Zahl annehmen.
     SingleSwitchEnergy = 100000;
    }
   }
  }
 }

 if (SubState == RelSubStates::Delay2) // Die noch folgende Wartezeit bis zum nächsten Puls
 {
#ifdef RELAYUSEDISCRETETIMING
  if ((signed)(time-NextPointInTime) >= 0)
  //if ((time-PulseStartTime) >= RELAYPOSTDELAY)
#else
  if ((signed)(time-NextPointInTime) > 0)
  //if ((time-PulseStartTime) > RELAYPOSTDELAY)
#endif
  {
   SubState = RelSubStates::Idle;
  }
 }

 // Folgend die Verwaltung der Operating States der Relay-Unit
 // ==========================================================
 if ((OpState == RelOperatingStates::MeasMode) && (SingleSwitchEnergy))
 { // Messung wurde bereits durchgeführt, warten bis erreichen der Mindestreserve für's BusVoltageFailureSwitching
  if (OpChgReq & (RELREQSTOP | RELREQBUSVFAIL))
  { // Wenn währenddessen der Start schon wieder abgeblasen wurde...
   OpState = RelOperatingStates::Disable;
   OpChgReq = 0;
  } else {
   if (CalcAvailRelEnergy() >= __builtin_popcount(BusVFailMask))
   {
    for (unsigned ch=0; ch<CHANNELCNT; ch++)
     PulseRepTmr[ch] = time; // Die PulseRepTmr werden auf "fällig" gesetzt
    OpState = RelOperatingStates::Operating;
   }
  }
 }

 int RelEnergyAvail=0;
 bool StartASwitch = false;

 if (OpState == RelOperatingStates::Disable)
 {
  if (OpChgReq & (RELREQSTOP | RELREQBUSVFAIL))
  {
   OpChgReq = 0; // Dann auch einen evtl StartRequest löschen
  }
  if (OpChgReq & RELREQSTART)
  {
   // Bulkspannung speichern
   EnergyCalcRefVoltage = GetRailVoltage();
   // Wenn Bulkspannung > fester Wert
   if (EnergyCalcRefVoltage > MINURAILINITVOLTAGE)
   {
    // Es wird das erste Relais bestromt mit der alten Schaltrichtung,
    // d.h. es wird nicht umgeschaltet. Dies dient nur zur Messung,
    // um wieviel die Bulkspannung dabei einbricht.
    if (ChRealSwStatus & 1)
    {
     DriverData = RELAYPATTERNON;
    } else {
     DriverData = RELAYPATTERNOFF;
    }
    PulseRepTmr[0] = time + RELAYREPPULSEDELAYLONG;
    OpState = RelOperatingStates::MeasMode;
    NextPointInTime = time + RELAYPULSEDURATION;
    SubState = RelSubStates::Pulse;
    retval = true;
    OpChgReq &= 0;
   }
  }
 }

 if ((OpState == RelOperatingStates::BusVFail) && (SubState == RelSubStates::Idle))
 {
  OpState = RelOperatingStates::Disable;
 }

 if ((OpState == RelOperatingStates::Operating) && (SubState == RelSubStates::Idle))
 {
  if ((OpChgReq & RELREQBUSVFAIL))
  {
   if (BusVFailMask)
   { // Es gibt Kanäle, die für ein BusVoltageFailureSwitching konfiguriert sind
    DriverData = 0;
    // Die Routine ist zwar ähnlich wie die "normale" Schaltroutine, doch leider zu unerschiedlich um sie ohne weiteres zu vereinigen.
    for (unsigned ch=0;ch<CHANNELCNT;ch++)
    {
     if (BusVFailMask & (1 << ch))
     {
      //BusVFailMask &= ~(1 << ch); unnötig
      if (BusVFailData & (1 << ch))
      {
       ChTargetSwStatus |= (1 << ch);
       ChRealSwStatus |= (1 << ch);
       DriverData |= (RELAYPATTERNON << (2*ch));
      } else {
       ChTargetSwStatus &= ~(1 << ch);
       ChRealSwStatus &= ~(1 << ch);
       DriverData |= (RELAYPATTERNOFF << (2*ch));
      }
     }
    }
    NextPointInTime = time + RELAYPULSEDURATION;
    SubState = RelSubStates::Pulse;
    OpState = RelOperatingStates::BusVFail;
    retval = true;
   } else { // kein BusVoltageFailureSwitching, dann geht es hier ganz einfach
    OpState = RelOperatingStates::Disable;
   }
   OpChgReq = 0;
  } else {
   if ((OpChgReq & RELREQSTOP))
   { // Es wurde ein Stop verlangt, dann gibt es kein BusVoltageFailureSwitching!
    OpState = RelOperatingStates::Disable;
    OpChgReq = 0;
   } else {
    if (BuffersNonEmpty())
    {
     // Für wie viele Relais reicht die gespeicherte Energie?
     RelEnergyAvail = CalcAvailRelEnergy() - __builtin_popcount(BusVFailMask);
     if (RelEnergyAvail > 0)
      StartASwitch = true;
    } else
     if (IdleDetect(time))
      if ((CalcAvailRelEnergy() - __builtin_popcount(BusVFailMask)) > 0)
      {
       // Nix los, Elkos voll.
       // Mal nachgucken, ob eine Pulswiederholung ansteht.
       // Wenn ein Kanal geschaltet worden ist, wird später noch mal ein Puls nachgelegt.
       int oldest_ch = -1;
       int oldest_age = -1;
       int age;
       for (int ch=0; ch < CHANNELCNT; ch++)
       {
        age = (signed)(time-PulseRepTmr[ch]);
        if (age >= 0)
        {
         if (age > oldest_age)
         {
          oldest_ch = ch;
          oldest_age = age;
         }
        }
       }
       if (oldest_ch >= 0)
       {
        PulseRepTmr[oldest_ch] = time + RELAYREPPULSEDELAYLONG;
        int mask = 1 << oldest_ch;
        if (ChRealSwStatus & mask)
        {
         DriverData = RELAYPATTERNON << (2*oldest_ch);
        } else {
         DriverData = RELAYPATTERNOFF << (2*oldest_ch);
        }
        NextPointInTime = time + RELAYPULSEDURATION;
        SubState = RelSubStates::Pulse;
        retval = true;
       }
      }
   }
  }
 }

 // Nachfolgend wird das Ansteuermuster für die Relaistreiber generiert.
 // Die Routine wird aus einem Auftrag so viele Schalthandlungen raushohlen, wie Energie zur Verfügung
 // steht (wenn gewünscht) oder umgekehrt den Schaltauftrag zusammenhalten und erst ausführen,
 // wenn genug Energie zur Verfügung steht (wenn RELAYKEEPTASKSTOGETHER definiert).

 // Die Routine kann auch mehrere Aufträge zusammenfassen, wenn die Energie reicht (unter Beachtung
 // von RELAYKEEPTASKSTOGETHER). Es ist durch DoEnqueue() sichergestellt, dass ein Kanal nie mehr als
 // einmal in der Warteschlage vorkommt, deshalb ist das unproblematisch.
 if (StartASwitch)
 {
  int RelEnergyNeeded;
  bool AnotherLoop = false;
  DriverData = 0;
  do
  {
#ifdef RELAYKEEPTASKSTOGETHER
   RelEnergyNeeded = __builtin_popcount(Buffer[BufRdPtr].Mask); // Zähle gesetzte Bits in .Mask
#else
   RelEnergyNeeded = 1;
#endif
   if (RelEnergyAvail < RelEnergyNeeded)
   {
    break;
   }
   for (unsigned ch=0;ch<CHANNELCNT;ch++)
   {
    if (Buffer[BufRdPtr].Mask & (1 << ch))
    {
     Buffer[BufRdPtr].Mask &= ~(1 << ch);
     ChForcedSwMsk &= ~(1 << ch);
     PulseRepTmr[ch] = time + RELAYREPPULSEDELAY;
     if (Buffer[BufRdPtr].Bits & (1 << ch))
     {
      ChRealSwStatus |= (1 << ch);
      DriverData |= (RELAYPATTERNON << (2*ch));
     } else {
      ChRealSwStatus &= ~(1 << ch);
      DriverData |= (RELAYPATTERNOFF << (2*ch));
     }
     if ((--RelEnergyAvail == 0) || (Buffer[BufRdPtr].Mask == 0))
     {
      break;
     }
    }
   }
   if (Buffer[BufRdPtr].Mask == 0)
   {
    AnotherLoop = NextBufEntry(BufRdPtr);
   }
  } while (AnotherLoop);
  if (DriverData != 0)
  {
   NextPointInTime = time + RELAYPULSEDURATION;
   SubState = RelSubStates::Pulse;
   retval = true;
  }
 }
 if (retval && (DriverData != 0))
  pwmEnable(true);
 RelDriverData = DriverData;
 return retval;
}