AWeX Port Override

Go To Last Post
2 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I'm using an ATXMEGA64A3U to drive a couple of simple DC motors using a pair of H-Bridges connected to PORTC. They draw moderate operating current, except when stalled at the end of travel, when I need to limit the current to 10A.

I have fast control of the bottom switches and slow control of the top, and all port pin signals are active-high - that is the output is 1 to close the switch.

I don't need to change direction quickly, just high speed bottom switch drive for current control. So to drive a motor, I close a top switch then regulate current using the opposite bottom switch. When the switch is closed, the current increases. When the switch opens, current recirculates around the top switches and decays. I have a series output inductor to limit the rate of current rise/fall.

I'm using the analogue comparator to detect excessive current, and plan to use the event system to force the bottom switch off for a fixed time using TCC0. I've set up the timer to give a 2us pulse every 20us, as a low duty-cycle disable signal. The over-current event can reset the timer extremely quickly, without CPU intervention, forcing the current to decay from the limit, then re-enabling the bottom switch to keep the current flowing until it next exceeds the limit.

BUT... this is proving to be very difficult! The timer outputs a PWM signal which begins high, and I can't change that. Since the current-limit event resets the timer, the high state must be used to disable the bottom switch. So I have configured the port pin as inverted, and initialised it as set (as a disable signal). By using AWeXC in common waveform channel mode, I can select the PWM signal to any PORTC pin of my choice. However, all of the switch signals which are not PWM selected in OUTOVEN become output as high, which will destroy the H-Bridges.

The Atmel documentation on the AWeX is sparse, and I have resorted to experimentation to fill in the gaps. But figure 16.2 in the AU manual just seems to be plain wrong! According to that figure, with DTICCxEN set, the port pin state is routed from either the common waveform channel if OUTOVENx set, or from the PORTC.OUT register if not set. But with OUTOVENx all set to 0, the port pin is high no matter what is written to the OUT register.

My test code in included below. I'd be very happy if I have misunderstood something which can be corrected, but I fear that there is an undocumented error in the silicon, or the data sheet. Can anyone shed any light on this?

void function_init (void)
{
  // Initialise PORTC
  //  - Configure bottom switch drives as inverted so PWM can be used to DISABLE
  //    on comparator for current limit control.
  PORTC_PIN0CTRL = PINCTRL_TTLOUTLOW;  // WIN_B1
  PORTC_PIN1CTRL = PINCTRL_TTLOUT;     // WIN_T1
  PORTC_PIN2CTRL = PINCTRL_TTLOUTLOW;  // WIN_B2
  PORTC_PIN3CTRL = PINCTRL_TTLOUT;     // WIN_T2
  PORTC_PIN4CTRL = PINCTRL_TTLOUTLOW;  // CUR_B1
  PORTC_PIN5CTRL = PINCTRL_TTLOUT;     // CUR_T1
  PORTC_PIN6CTRL = PINCTRL_TTLOUTLOW;  // CUR_B2
  PORTC_PIN7CTRL = PINCTRL_TTLOUT;     // CUR_T2
  PORTC_OUT      = 0;//ALL_B;
  PORTC_DIRSET   = 0xFF;

  // Configure TCC0 and AWeX to drive window +ve so event-driven fault 
  // handling can be tried
  TCC0.CTRLA    = 0x00;        // Set prescaler to 0 to disable timer until setup complete
  TCC0.CTRLB    = 0x03;        // Set waveform to SS PWM, all CCxEN outputs disabled
  TCC0.CTRLC    = 0x00;        // Set Compare Outputs to 0
  TCC0.CTRLD    = 0x00;        // Timer Event is unused
  TCC0.CTRLE    = 0x00;        // Leave the timer in 16-bit mode
  TCC0.INTCTRLA = 0x00;        // Leave interrupts disabled
  TCC0.INTCTRLB = 0x00;        // Leave interrupts disabled
  TCC0.CTRLFCLR = 0xFF;        // Command nothing, set counting to up
  TCC0.CNT      = 0x0000;      // Clear counter
  TCC0.PER      = 640;         // Set period (20us) in cycles at 32MHz
  TCC0.CCA      = 64;          // Set CCA pulse time (2us) in cycles at 32MHz
  TCC0.CCB      = 0x0000;
  TCC0.CCC      = 0x0000;
  TCC0.CCD      = 0x0000;

  AWEXC.CTRL    = 0x1F;        // Enable common waveform channel mode (CCA), and set all DTICCxEN
  AWEXC.FDEMASK = 0x00;        // Disable fault events for now
  AWEXC.FDCTRL  = 0x00;        // Disable fault protection for now
  AWEXC.DTLSBUF = 0x00;        // Preset OUTOVEN double buffer to disable all PWM outputs
  AWEXC.DTHSBUF = ALL_B;       // Preset OUT double buffer to disable all bottom switches
  AWEXC.OUTOVEN = 0x00;        // Disable PWM output on all pins for now
  PORTC_OUT     = ALL_B;       // Disable all top switches (OUT) and bottom switches (OUTLOW)

  TCC0.CTRLA    = 0x01;        // Set prescaler to DIV1 (32MHz) to start timer
  TCC0.CTRLFSET = 0x08;        // Command TCx0 to RESTART

  // Setup complete - now configure AWeX to drive Window in +ve direction
  PORTC.OUTSET  = WIN_T1;      // Enable WIN_T1 to drive Window +ve
  AWEXC.OUTOVEN = WIN_B2;      // Enable PWM output on WIN_B2
}

Electronic components work on the principle of smoke; I know this because when I let the smoke out, they stop working. Also, sanity is over-rated.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Er, I do now think it's me, Freaky Folks. I had some other code running which shouldn't have been, and that was modifying PORTC. After a good deal of searching, removing all other references to PORTC and doing a good tidy up, it seems to be operating more as I expected.

Lesson for today: check what else is stamping on the peripheral you're struggling to debug.

Embarrassed newbie... :oops:

Electronic components work on the principle of smoke; I know this because when I let the smoke out, they stop working. Also, sanity is over-rated.