6 PINUS软件

原文链接

PINUS 代码部分

整个代码是在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;
}

阻塞换相(Block Commutation)

三相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。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值