标签:
整个代码是在DAVE写的,DAVE是一个基于Eclipse的IDE,它包含一个标准C编码环境和一些预定义的文件。
PINUS板子的代码部分,负责分发LARIX发送给4个电机的数据,并通过3项阻塞通信来控制这些电机。
菊花链协议,是基于串口来连接板和板之间的通信。因此,需要提供一些参数,比如缓冲区大小,停止字节,消息数据的长度,这些都在DaisyCodes.h里面定义了。这些代码对于建立数据传输链路是必不可少的。
#ifndef DAISYCODES_H_
#define DAISYCODES_H_
#define SET_REF_CURRENT 34
#define DAISY_BUFFER_SIZE 13
#define DAISY_MESSAGE_LENGTH 3
#define DAISY_STOP_BYTE 4
#endif /* DAISYCODES_H_ */
DaisyChain.c包含了有关接收13字节的代码,它会为当前电机抽取前3个字节数据,把剩下的数据移到消息包的开头位置,并把它传递给下一个PINUS板。
#include <DAVE3.h>
#include "DaisyChain.h"
uint8_t FifoRecBuffer[DAISY_BUFFER_SIZE] = {0};
uint8_t FifoTransBuffer[DAISY_BUFFER_SIZE] = {0};
uint8_t DaisyTimeOut = 1;
uint8_t DaisyCount = 0;
void DaisyChain(void)
{
uint8_t i=0;
status_t status=0;
uint32_t data=0;
if (DaisyTimeOut)
StopMotor();
if(USIC_GetRxFIFOFillingLevel(UART001_Handle0.UartRegs) >= DAISY_BUFFER_SIZE)
{
//Read data from UART buffer
UART001_ReadDataBytes(&UART001_Handle0,FifoRecBuffer,DAISY_BUFFER_SIZE);
//Assumption that communication is lost --> emtpy Receive Buffer
if (FifoRecBuffer[DAISY_BUFFER_SIZE-1] != DAISY_STOP_BYTE)
{
IO004_TogglePin(IO004_Handle1);
USIC_FlushRxFIFO(UART001_Handle0.UartRegs);
return;
}
uint8_t cmd = FifoRecBuffer[0];
uint16_t params = (FifoRecBuffer[1] << 8 | FifoRecBuffer[2]);
switch (cmd)
{
case SET_REF_CURRENT:
SetReferenceCurrent(params);
break;
}
for(i=DAISY_MESSAGE_LENGTH; i<DAISY_BUFFER_SIZE-1; i++)
FifoTransBuffer[i-DAISY_MESSAGE_LENGTH]=FifoRecBuffer[i];
//Status-Code
FifoTransBuffer[i-DAISY_MESSAGE_LENGTH]=status;
i++;
//Data
FifoTransBuffer[i-DAISY_MESSAGE_LENGTH]=(uint8_t)(data >> 8);
i++;
FifoTransBuffer[i-DAISY_MESSAGE_LENGTH]=(uint8_t)data;
i++;
FifoTransBuffer[i-DAISY_MESSAGE_LENGTH]=DAISY_STOP_BYTE;
UART001_WriteDataBytes(&UART001_Handle0, FifoTransBuffer, DAISY_BUFFER_SIZE);
DaisyTimeOut = 0;
DaisyCount++;
}
}
void InitDaisyWatchDog()
{
//Watchdog
CCU40_CC41->PSC |= 0x03;
CCU40_CC41->PRS = 0xFFFF;
CCU40_CC41->CRS = 0;
CCU40->GCSS |= (0x01UL << 4);
//Interrupt Compare Match Slice 1
CCU40_CC41->INTE |= 0x04UL;
CCU40_CC41->SRS |= 0x04UL;
NVIC_SetPriority((IRQn_Type)22, 1);
NVIC_EnableIRQ((IRQn_Type)22);
//Enable slice
CCU40->GIDLC |= 0x01UL << 1;
CCU40_CC41->TCSET |= 0x01UL;
}
void DaisyWatchDog_ISR()
{
static uint8_t lastCount;
if (lastCount == DaisyCount) DaisyTimeOut = 1;
lastCount = DaisyCount;
}
Main.c文件初始化了所有的必要函数,在主循环中,调用了DaisyChain()函数。
#include <DAVE3.h> //Declarations from DAVE3 Code Generation (includes SFR declaration)
#include "BlockCommutation.h"
#include "ADC.h"
#include "DaisyChain.h"
int main(void){
DAVE_Init(); // Initialization of DAVE Apps
InitBlockCommutation();
InitADC();
InitDaisyWatchDog();
while(1){
DaisyChain();
}
return 0;
}
三相BLDC电机需要一个软件控制器,这部分代码在BlockCommutation.c里面。代码负责由PWM信号产生旋转场(rotating field),利用MOSFET和对应的MOSFET驱动。
#include "BlockCommutation.h"
volatile float InnerPWMFreq=25000;
volatile float CurrentDutyCycleStart=0.1;
volatile uint32_t InnerPWMPeriod=0;
volatile uint32_t InnerPWMCompare=0;
volatile int8_t PhaseState=0;
volatile enum MotorState motorState = Stopped;
void InitBlockCommutation()
{
//Set Period and Compare for all slices
InnerPWMPeriod=((uint32_t)(1000000000.0f/(InnerPWMFreq*31.25)))-(uint32_t)1;
InnerPWMCompare=InnerPWMPeriod*CurrentDutyCycleStart;
CCU80_CC80->PRS = CCU80_CC81->PRS = CCU80_CC82->PRS = CCU80_CC83->PRS = InnerPWMPeriod;
CCU80_CC80->CR1S = InnerPWMCompare;
CCU80_CC80->CR2S = InnerPWMPeriod+1;
CCU80_CC81->CR1S = 0;
CCU80_CC81->CR2S = 0;
CCU80_CC82->CR1S = 0;
CCU80_CC82->CR2S = InnerPWMPeriod+1;
CCU80_CC83->CR1S = InnerPWMCompare-1;//>>1;
CCU80_CC83->CR2S = InnerPWMCompare-1;//>>1;
CCU80->GCSS |= 0x1111UL;
//Synchronos start
CCU80_CC80->INS |= 0x10007UL;
CCU80_CC80->CMC |= 0x1UL;
CCU80_CC81->INS |= 0x10007UL;
CCU80_CC81->CMC |= 0x1UL;
CCU80_CC82->INS |= 0x10007UL;
CCU80_CC82->CMC |= 0x1UL;
CCU80_CC83->INS |= 0x10007UL;
CCU80_CC83->CMC |= 0x1UL;
//Enable slices
CCU80->GIDLC |= 0xFUL;
//CCU8 Channel Selection
CCU80_CC80->CHC |= 0x1E;
CCU80_CC81->CHC |= 0x1E;
CCU80_CC82->CHC |= 0x1E;
//IO CCU8
PORT0->IOCR0 |= 0x15UL << 3; //P0.0 UH
PORT0->IOCR0 |= 0x15UL << 27; //P0.3 UL
PORT0->IOCR4 |= 0x15UL << 27; //P0.7 VH
PORT0->IOCR4 |= 0x15UL << 3; //P0.4 VL
//The startup software (SSW) will change the PC8 value to input pull-up device active, 00010b.
PORT0->IOCR8 = 0x00UL;
PORT0->IOCR8 |= 0x15UL << 3; //P0.8 WH
PORT0->IOCR8 |= 0x15UL << 27; //P0.11 WL
//Blockcommutation
CCU40_CC40->PSC |= 0x07;
CCU40_CC40->PRS = 0xFFFF;
CCU40_CC40->CRS = 0;
CCU40->GCSS |= (0x01UL << 0);
//Interrupt Compare Match Slice 0
CCU40_CC40->INTE |= 0x04UL;
NVIC_SetPriority((IRQn_Type)21, 0);
NVIC_EnableIRQ((IRQn_Type)21);
//Enable slice
CCU40->GIDLC |= 0x01UL;
//ADC Trigger
CCU80_CC83->SRS |= 2UL<<4;
CCU80_CC83->SRS |= 1UL<<2;
CCU80_CC83->INTE |= 1UL<<2;
}
void BlockCommutation_ISR()
{
if (motorState == Running)
{
PhaseState++;
if (PhaseState > 5)
PhaseState = 0;
switch (PhaseState)
{
case 0:
VADC_G0->ASSEL = 0x04UL;
CCU80_CC80->CR1S = InnerPWMCompare;
CCU80_CC80->CR2S = InnerPWMPeriod+1;
CCU80_CC81->CR1S = 0;
CCU80_CC81->CR2S = 0;
CCU80_CC82->CR1S = 0;
CCU80_CC82->CR2S = InnerPWMPeriod+1;
break;
case 1:
VADC_G0->ASSEL = 0x02UL;
CCU80_CC80->CR1S = InnerPWMCompare;
CCU80_CC80->CR2S = InnerPWMPeriod+1;
CCU80_CC81->CR1S = 0;
CCU80_CC81->CR2S = InnerPWMPeriod+1;
CCU80_CC82->CR1S = 0;
CCU80_CC82->CR2S = 0;
break;
case 2:
VADC_G0->ASSEL = 0x01UL;
CCU80_CC80->CR1S = 0;
CCU80_CC80->CR2S = InnerPWMPeriod+1;
CCU80_CC81->CR1S = InnerPWMCompare;
CCU80_CC81->CR2S = InnerPWMPeriod+1;
CCU80_CC82->CR1S = 0;
CCU80_CC82->CR2S = 0;
break;
case 3:
VADC_G0->ASSEL = 0x04UL;
CCU80_CC80->CR1S = 0;
CCU80_CC80->CR2S = 0;
CCU80_CC81->CR1S = InnerPWMCompare;
CCU80_CC81->CR2S = InnerPWMPeriod+1;
CCU80_CC82->CR1S = 0;
CCU80_CC82->CR2S = InnerPWMPeriod+1;
break;
case 4:
VADC_G0->ASSEL = 0x02UL;
CCU80_CC80->CR1S = 0;
CCU80_CC80->CR2S = 0;
CCU80_CC81->CR1S = 0;
CCU80_CC81->CR2S = InnerPWMPeriod+1;
CCU80_CC82->CR1S = InnerPWMCompare;
CCU80_CC82->CR2S = InnerPWMPeriod+1;
break;
case 5:
VADC_G0->ASSEL = 0x01UL;
CCU80_CC80->CR1S = 0;
CCU80_CC80->CR2S = InnerPWMPeriod+1;
CCU80_CC81->CR1S = 0;
CCU80_CC81->CR2S = 0;
CCU80_CC82->CR1S = InnerPWMCompare;
CCU80_CC82->CR2S = InnerPWMPeriod+1;
break;
}
CCU80_CC83->CR1S = InnerPWMCompare-1;//>>1;
CCU80_CC83->CR2S = InnerPWMCompare-1;//>>1;
CCU80->GCSS |= 0x1111;
// --- all shadow registers set?
while ((CCU80->GCST & 0x1111) != 0);
CCU80_CC83->INTE |= 1UL<<4;
}
else
motorState=Running;
}
uint8_t GetPhaseState()
{
return PhaseState;
}
void StartMotor()
{
//Start slices
SCU_GENERAL->CCUCON |= 0x100UL;
SCU_GENERAL->CCUCON &= ~(0x100UL);
//Start slices
CCU40_CC40->TCSET |= 0x01UL;
motorState=Starting;
}
void StopMotor()
{
InnerPWMCompare=InnerPWMPeriod*CurrentDutyCycleStart;
//Stop slices CCU4
CCU40_CC40->TCCLR |= 3UL;
//Stop slices CCU8
CCU80_CC80->TCCLR |= 3UL;
CCU80_CC81->TCCLR |= 3UL;
CCU80_CC82->TCCLR |= 3UL;
CCU80_CC83->TCCLR |= 3UL;
motorState=Stopped;
}
void SetReferenceCurrent(uint16_t ref)
{
if (motorState == Stopped && ref > 130)
StartMotor();
else if(motorState != Stopped && ref <= 130)
StopMotor();
if (motorState == Running)
InnerPWMCompare=ref;
}
BLDC 电机的阻塞通信控制需要能测量输出电流的相位。这通过ACD.c读取XMC的模拟输入端口获取。
#include "ADC.h"
volatile uint16_t ADCReference=0;
void InitADC()
{
//Converter is permanently on
VADC_G0->ARBCFG |= 0x83UL;
VADC_G1->ARBCFG |= 0x83UL;
//Start-Up Calibration
VADC->GLOBCFG |= 1UL << 31;
VADC->GLOBCFG |= 1UL << 31;
while(VADC_G0->ARBCFG & (1UL<<28) || VADC_G1->ARBCFG & (1UL<<28));
//Priority Channel
VADC_G0->CHASS |= 0x07UL;
VADC_G1->CHASS |= 0x02UL;
//Input class
VADC_G0->CHCTR[0] |= 0x341UL;
VADC_G0->CHCTR[1] |= 0x341UL;
VADC_G0->CHCTR[2] |= 0x341UL;
VADC_G0->RCR[0] |= 1UL <<31;
VADC_G1->CHCTR[1] |= 1UL;
VADC_G1->CHCTR[1] |= 1UL << 16;
VADC_G1->RCR[1] |= 1UL <<31;
//External Trigger
VADC_G0->ASCTRL |= 0xC800UL;
VADC_G1->ASCTRL |= 0xC800UL;
//Gating mode
VADC_G0->ASMR |= 0x05UL;
VADC_G1->ASMR |= 0x05UL;
//Channel Select
VADC_G0->ASSEL = 0x04UL;
VADC_G1->ASSEL = 0x02UL;
//Enable Arbitration slot
VADC_G0->ARBPR |= 0x01UL << 25;
VADC_G1->ARBPR |= 0x01UL << 25;
//Service Request Software Activation Trigger
VADC_G0->SRACT |= 0x02UL;
VADC_G0->REVNP0 |= 1UL << 0;
NVIC_SetPriority((IRQn_Type)18, 0);
NVIC_EnableIRQ((IRQn_Type)18);
VADC_G1->SRACT |= 0x02UL;
VADC_G1->REVNP0 |= 1UL << 4;
NVIC_SetPriority((IRQn_Type)20, 2);
NVIC_EnableIRQ((IRQn_Type)20);
//IO enable
PORT2->PDISC &= (~((uint32_t)0x1U << 6)); //Pin 2.6
PORT2->PDISC &= (~((uint32_t)0x1U << 8)); //Pin 2.8
PORT2->PDISC &= (~((uint32_t)0x1U << 9)); //Pin 2.9
PORT2->PDISC &= (~((uint32_t)0x1U << 7)); //Pin 2.7
}
void ZeroCrossing_ISR()
{
if(VADC_G0->RES[0] & (1UL << 31))
{
if((GetPhaseState() % 2 == 0 && ((uint16_t) VADC_G0->RES[0]) < ADCReference) ||
(GetPhaseState() % 2 != 0 && ((uint16_t) VADC_G0->RES[0]) > ADCReference))
{
CCU40_CC40->TCCLR|=0x02;
CCU80_CC83->INTE &= ~(1UL<<4);
IO004_TogglePin(IO004_Handle0);
}
}
}
void ReferenceResult_ISR()
{
if(VADC_G1->RES[1] & (1UL << 31))
ADCReference = VADC_G1->RES[1];
}
这部分代码使用了如下DAVE的工具,例如ADC, UART, NVIC和IO。
标签:
原文地址:http://blog.csdn.net/duinodu/article/details/51924475