cvl-robot's diary

研究ノート メモメモ https://github.com/dotchang/

特性の分からない3相DCブラシレスモーターをソフトウェアエンコーダを搭載したTiのマイコンボードLAUNCHXL-F28069MとモータドライバBOOSTXL-DRV8305EVMを使って動かす(その6)

(編集中)
アナログ入出力だけでなく、シリアル接続なども使えた方がシステム構築には便利です。
ただ、C2000シリーズのマイコンでSCI(UART)接続しようというのは、Linuxの10倍ぐらい面倒くさいです。

Githubからサンプルプログラム

LAUNCHXL-F28027F+BOOSTXL-DRV8305EVMの組み合わせで、SCI(UART)を使うサンプルプロジェクトとして、こちらの掲示板の
InstaSPIN F28069MPZT : how to use UART/SCI communication to terminal? - InstaSPIN Motor Solutions Forum - C2000™ Microcontrollers - TI E2E Community
のスレッドで紹介されているAndrew Buckinさんのproj_lab05aの改造版
github.com
を参照すると、理解が早そうです。

ソースコードのdiffを取って、変更箇所を見ていきましょう。6つのソースファイルがあります。

proj_lab05a.c
hal/hal.c
hal/hal.h
hal/hal_obj.h
sci/sci.c
sci/sci.h

比較元のファイルの場所は、次の通りです。
C:\ti\motorware\motorware_1_01_00_16\sw\solutions\instaspin_foc\src
C:\ti\motorware\motorware_1_01_00_16\sw\modules\hal\boards\boostxldrv8305_revA\f28x\f2806x\src
C:\ti\motorware\motorware_1_01_00_16\sw\drivers\sci\src\32b\f28x\f2802x

proj_lab05a.c

// **************************************************************************
// the defines

#define uint8_t char

#define ECHO_ON 1 // set 1 to show input and 0 to disable it

#define LED_BLINK_FREQ_Hz   5

#define BUF_LEN 8 // length of the command buffer


// **************************************************************************
// the globals

uint32_t ECap1IntCount = 0;
uint32_t CAP_DATA[] = {0,0/*,0,0*/};

char cmdBuf[BUF_LEN]; // Input/command buffer
uint8_t bufPos = 0; // Position of the next char in the buffer
uint8_t cmdReady = 0; // Indicates that a command is ready for execution and blocks further input until reset to 0.

//Added by Maya
#ifdef SCI
	char * msg;
	uint16_t ReceivedChar = 0;
	//uint16_t RXISRCount = 0;
	//uint16_t SysCounter = 0;

#endif
//Added by Maya
#ifdef SCI

interrupt void sciaISR(void) {
	//RXISRCount++;

	ReceivedChar = HAL_sciaRead(halHandle) & 0x00FF;

	//Handling escape.
	if(ReceivedChar != 27){
		//Handling carriage return/new line.
		if(ReceivedChar != '\r' && ReceivedChar != '\n' && cmdReady == 0){
			//Show input.
			if(ECHO_ON){
				HAL_sciaWrite(halHandle, ReceivedChar);
			}
			//Handling backspace/delete.
			if(ReceivedChar != 127 && ReceivedChar != 8){
				bufPos++;
				//If the end of the buffer wasn't reached, add new char to the buffer.
				if(bufPos < BUF_LEN){
					cmdBuf[bufPos-1] = (char)ReceivedChar; //Adding char.
					cmdBuf[bufPos] = '\0'; //Appending null to indicate the end of the string.
				}
			}else{
				//If the beginning of the buffer wasn't reached, remove the previous char from the buffer.
				if(bufPos > 0){
					bufPos--;
					//Only delete if within buffer range.
					if(bufPos < BUF_LEN){
						cmdBuf[bufPos] = '\0';
					}
				}
			}
		}else if(cmdReady == 0){ //If enter was pressed, start new line and set cmdReady flag.
			msg = "\n\r";
			HAL_sciaWriteMsg(halHandle, msg);
			cmdReady = 1;
		}
	}else{ //If escape is pressed, reset command buffer and clear cmdReady flag.
		cmdReady = 0;
		bufPos = 0;
		cmdBuf[0] = '\0';
	}

	HAL_sciaClearRxFifoOvf(halHandle);
	HAL_sciaClearRxFifoInt(halHandle);

	HAL_pieAckInt(halHandle,PIE_GroupNumber_9);		// Issue PIE ack INT9

	return;
}

#endif
//Added by Dmitri Ranfft on 16.09.2015
#ifdef CAP
__interrupt void ecap1ISR(void)
{
	//scia_msg("interrupt\n\r");
    // Cap input is syc'ed to SYSCLKOUT so there may be
    // a +/- 1 cycle variation

	CAP_DATA[0] = CAP_getCap1(halHandle->capHandle);
	CAP_DATA[1] = CAP_getCap2(halHandle->capHandle);
	//CAP_DATA[2] = CAP_getCap3(halHandle->capHandle);
	//CAP_DATA[3] = CAP_getCap4(halHandle->capHandle);

    ECap1IntCount++;

    CAP_clearInt(halHandle->capHandle, CAP_Int_Type_CEVT2);
    CAP_clearInt(halHandle->capHandle, CAP_Int_Type_Global);
    CAP_rearm(halHandle->capHandle);

    // Acknowledge this interrupt to receive more interrupts from group 4
    PIE_clearInt(halHandle->pieHandle, PIE_GroupNumber_4);
}
#endif

eCAPというのが、また聞きなれないC2000特有の機能で、こちらに解説があります。
C2000の便利なeCAP機能を使って見ましょう - プロセッサ(DSP / ARM / MCU) - Japanese E2E (日本語コミュニティ) - TI E2E Community

hal

hal.c

607--609

  // Added by Dmitri Ranfft on 16.09.2015
  // Initialize the eCAP
  obj->capHandle = CAP_init((void *)CAP1_BASE_ADDR, sizeof(CAP_Obj));

652--656

  //Added by Maya
  #ifdef SCI
  	// Init SCI A registers
  	obj->sciaHandle = SCI_init((void *) SCIA_BASE_ADDR, sizeof(SCI_Obj));
  #endif

787--795

 //Added by Maya
#ifdef SCI
 HAL_setupSCI(handle);
#endif

 //Added by Dmitri Ranfft on 16.09.2015
#ifdef CAP
 HAL_setupCAP(handle);
#endif

994--1020

  // PWMC_H
  // Edited by Dmitri Ranfft on 16.09.2015 (changed from EPWM3 to 4)
  GPIO_setMode(obj->gpioHandle,GPIO_Number_6,GPIO_6_Mode_EPWM4A);

  // PWMC_L
  // Edited by Dmitri Ranfft on 16.09.2015 (changed from EPWM3 to 4)
  GPIO_setMode(obj->gpioHandle,GPIO_Number_7,GPIO_7_Mode_EPWM4B);

  // eCAP1
  // Added by Dmitri Ranfft on 16.09.2015
  GPIO_setPullUp(obj->gpioHandle, GPIO_Number_5, GPIO_PullUp_Enable);
  GPIO_setQualification(obj->gpioHandle, GPIO_Number_5, GPIO_Qual_Sync);
  GPIO_setMode(obj->gpioHandle,GPIO_Number_5,GPIO_5_Mode_ECAP1);

    // EN_GATE
  // Edited by Dmitri Ranfft on 16.09.2015 (changed from GPIO 6 to 4)
  GPIO_setMode(obj->gpioHandle,GPIO_Number_4,GPIO_4_Mode_GeneralPurpose);
  GPIO_setLow(obj->gpioHandle,GPIO_Number_4);
  GPIO_setDirection(obj->gpioHandle,GPIO_Number_4,GPIO_Direction_Output);
  
    // WAKE
  // Edited by Dmitri Ranfft on 16.09.2015 (changed from GPIO 7 to 12)
  GPIO_setMode(obj->gpioHandle,GPIO_Number_12,GPIO_12_Mode_GeneralPurpose);
  GPIO_setHigh(obj->gpioHandle,GPIO_Number_12);
  GPIO_setDirection(obj->gpioHandle,GPIO_Number_12,GPIO_Direction_Output);

  // No Connection
  // Disabled by Dmitri Ranfft on 16.09.2015
  //GPIO_setMode(obj->gpioHandle,GPIO_Number_12,GPIO_12_Mode_GeneralPurpose);

修正前は、

  // PWMC_H
  GPIO_setMode(obj->gpioHandle,GPIO_Number_4,GPIO_4_Mode_EPWM3A);

  // PWMC_L
  GPIO_setMode(obj->gpioHandle,GPIO_Number_5,GPIO_5_Mode_EPWM3B);

    // EN_GATE
  GPIO_setMode(obj->gpioHandle,GPIO_Number_6,GPIO_6_Mode_GeneralPurpose);
  GPIO_setLow(obj->gpioHandle,GPIO_Number_6);
  GPIO_setDirection(obj->gpioHandle,GPIO_Number_6,GPIO_Direction_Output);
  
    // WAKE
  GPIO_setMode(obj->gpioHandle,GPIO_Number_7,GPIO_7_Mode_GeneralPurpose);
  GPIO_setHigh(obj->gpioHandle,GPIO_Number_7);
  GPIO_setDirection(obj->gpioHandle,GPIO_Number_7,GPIO_Direction_Output);

  // No Connection
  GPIO_setMode(obj->gpioHandle,GPIO_Number_12,GPIO_12_Mode_GeneralPurpose);

1037--1045

  // nFAULT
  //GPIO_setMode(obj->gpioHandle,GPIO_Number_28,GPIO_28_Mode_TZ2_NOT); // Edited by Dmitri Ranfft on 15.09.2015
  // SCI_RX
  GPIO_setMode(obj->gpioHandle,GPIO_Number_28,GPIO_28_Mode_SCIRXDA);

  // No connection (TX)
  //GPIO_setMode(obj->gpioHandle,GPIO_Number_29,GPIO_29_Mode_GeneralPurpose); // Edited by Dmitri Ranfft on 15.09.2015
  // SCI_TX
  GPIO_setMode(obj->gpioHandle,GPIO_Number_29,GPIO_29_Mode_SCITXDA);

修正前は、

  // nFAULT
  GPIO_setMode(obj->gpioHandle,GPIO_Number_28,GPIO_28_Mode_TZ2_NOT);

  // No connection (TX)
  GPIO_setMode(obj->gpioHandle,GPIO_Number_29,GPIO_29_Mode_GeneralPurpose);

1348--1502

//Added by Maya
void HAL_setupSCI(HAL_Handle handle) {
#ifdef SCI
	HAL_Obj *obj = (HAL_Obj *) handle;
	char *msg;
	//FIFO
	// SCIFFTX = 0xE040
		SCI_enableChannels(obj->sciaHandle);			// SCI reset
		SCI_enableTxFifoEnh(obj->sciaHandle);		// SCI FIFO transmit enable
		SCI_enableTxFifo(obj->sciaHandle);			// SCI FIFO transmit reset/reenable
		SCI_clearTxFifoInt(obj->sciaHandle);			// SCI clear FIFO transmit interrupt flag
		SCI_disableTxFifoInt(obj->sciaHandle);		// disable FIFO transmit interrupt
		SCI_setTxFifoIntLevel(obj->sciaHandle, SCI_FifoLevel_Empty);	// FIFO interrupt level
		// SCIFFRX = 0x2041
		SCI_enableRxFifo(obj->sciaHandle);			// SCI FIFO receive reset/reenable
		SCI_clearRxFifoInt(obj->sciaHandle);			// SCI clear FIFO receive interrupt flag
		SCI_disableRxFifoInt(obj->sciaHandle);		// disable FIFO receive interrupt
		SCI_setRxFifoIntLevel(obj->sciaHandle, SCI_FifoLevel_1_Word); // FIFO interrupt level

		SCI_enableRxFifoInt(obj->sciaHandle);

	// SCI stop bit, parity, loopback, char bits, idle/address mode (SCICCR = 0x07)
	SCI_setNumStopBits(obj->sciaHandle, SCI_NumStopBits_One);	// SCICCR bit 7
	SCI_setParity(obj->sciaHandle, SCI_Parity_Odd);				// SCICCR bit 6
	SCI_disableParity(obj->sciaHandle);							// SCICCR bit 5
	//SCI_enableParity(obj->sciaHandle);
	SCI_disableLoopBack(obj->sciaHandle);						// SCICCR bit 4
	SCI_setMode(obj->sciaHandle, SCI_Mode_IdleLine);			// SCICCR bit 3
	SCI_setCharLength(obj->sciaHandle, SCI_CharLength_8_Bits);// SCICCR bit 0-2

	// TX enable, RX enable, RX ERR INT enable, SLEEP, TXWAKE (SCICTL1 = 0x03)
	SCI_disableRxErrorInt(obj->sciaHandle);						// SCICTL1 bit 6
	SCI_disable(obj->sciaHandle);								// SCICTL1 bit 5
	SCI_disableTxWake(obj->sciaHandle);							// SCICTL1 bit 3
	SCI_disableSleep(obj->sciaHandle);							// SCICTL1 bit 2
	SCI_enableTx(obj->sciaHandle);								// SCICTL1 bit 1
	SCI_enableRx(obj->sciaHandle);								// SCICTL1 bit 0

	// TXINT enable, RXINT enable, TXEMPTY, TXRDY (SCICTL2 = 0x03)
	SCI_enableRxInt(obj->sciaHandle);							// SCICTL2 bit 1
	SCI_disableTxInt(obj->sciaHandle);							// SCICTL2 bit 0

	// SCIH-SCIL BAUD - SCI_BAUD = (LSPCLK/(SCI_BRR*8)) - 1
	SCI_setBaudRate(obj->sciaHandle, SCI_BaudRate_9_6_kBaud);

	// Reset SCI
	SCI_enable(obj->sciaHandle);

	msg = "\r\n\n  ********** SCI setup is done! **********\0";
	SCI_writeMsg(obj->sciaHandle, msg);
	//PIE_enableSciInt(obj->pieHandle, SCI_RXA);	// enable SCI interrupt
	PIE_enableInt(halHandle->pieHandle, PIE_GroupNumber_9, PIE_InterruptSource_SCIARX);
	CPU_enableInt(obj->cpuHandle, CPU_IntNumber_9);	// enable CPU interrupt

#endif // of SCI
}
#ifdef SCI
//Added by Maya
//SCIA
SCI_FifoStatus_e HAL_sciaGetRxFifoStatus(HAL_Handle handle) {
	HAL_Obj *obj = (HAL_Obj *) handle;
	return (SCI_getRxFifoStatus(obj->sciaHandle));
} // end of HAL_scigetRXFIFOStatus() function
//Added by Maya
void HAL_sciaWrite(HAL_Handle handle, const uint16_t data) {
	HAL_Obj *obj = (HAL_Obj *) handle;

	SCI_write(obj->sciaHandle, data);
}
//Added by Maya
void HAL_sciaWriteMsg(HAL_Handle handle, char * msg) {
	HAL_Obj *obj = (HAL_Obj *) handle;

	SCI_writeMsg(obj->sciaHandle, msg);
}
//Added by Maya
uint16_t HAL_sciaRead(HAL_Handle handle) {
	HAL_Obj *obj = (HAL_Obj *) handle;

	return (SCI_read(obj->sciaHandle));
}
//Added by Maya
void HAL_sciaClearRxFifoOvf(HAL_Handle handle) {
	HAL_Obj *obj = (HAL_Obj *) handle;
	SCI_clearRxFifoOvf(obj->sciaHandle);
}
//Added by Maya
void HAL_sciaClearRxFifoInt(HAL_Handle handle) {
	HAL_Obj *obj = (HAL_Obj *) handle;
	SCI_clearRxFifoInt(obj->sciaHandle);
}
//Added by Maya
void HAL_sciaClearTxFifoInt(HAL_Handle handle) {
	HAL_Obj *obj = (HAL_Obj *) handle;
	SCI_clearTxFifoInt(obj->sciaHandle);
}
void HAL_sciaEnableRxInt(HAL_Handle handle) {
	HAL_Obj *obj = (HAL_Obj *) handle;
	SCI_enableRxInt(obj->sciaHandle);
}
void HAL_sciaDisableRxInt(HAL_Handle handle) {
	HAL_Obj *obj = (HAL_Obj *) handle;
	SCI_disableRxInt(obj->sciaHandle);
}
void HAL_sciaEnableTxInt(HAL_Handle handle) {

	HAL_Obj *obj = (HAL_Obj *) handle;
	SCI_enableTxInt(obj->sciaHandle);
}
void HAL_sciaDisableTxInt(HAL_Handle handle) {
	HAL_Obj *obj = (HAL_Obj *) handle;
	SCI_disableTxInt(obj->sciaHandle);
}
bool HAL_sciaTxReady(HAL_Handle handle) {
	HAL_Obj *obj = (HAL_Obj *) handle;
	return (SCI_txReady(obj->sciaHandle));
}
bool HAL_sciaTxEmpty(HAL_Handle handle) {
	HAL_Obj *obj = (HAL_Obj *) handle;
	return (SCI_txEmpty(obj->sciaHandle));
}
bool HAL_sciaRxParityError(HAL_Handle handle) {
	HAL_Obj *obj = (HAL_Obj *) handle;
	return (SCI_rxParityError(obj->sciaHandle));
}
bool HAL_sciaRxOverrunError(HAL_Handle handle) {
	HAL_Obj *obj = (HAL_Obj *) handle;
	return (SCI_rxOverrunError(obj->sciaHandle));
}
bool HAL_sciaRxFrameError(HAL_Handle handle) {
	HAL_Obj *obj = (HAL_Obj *) handle;
	return (SCI_rxFrameError(obj->sciaHandle));
}
void HAL_sciaEnable(HAL_Handle handle) {
	HAL_Obj *obj = (HAL_Obj *) handle;
	SCI_enable(obj->sciaHandle);
}
void HAL_sciaDisable(HAL_Handle handle) {
	HAL_Obj *obj = (HAL_Obj *) handle;
	SCI_disable(obj->sciaHandle);
}
#endif //End of SCI
//Added by Maya, for PIE
void HAL_pieAckInt(HAL_Handle handle, const PIE_GroupNumber_e groupNumber) {
	HAL_Obj *obj = (HAL_Obj *) handle;
	PIE_clearInt(obj->pieHandle, groupNumber);
}
void HAL_enablePieInt(HAL_Handle handle) {
	HAL_Obj *obj = (HAL_Obj *) handle;
	PIE_enable(obj->pieHandle);
}
void HAL_disablePieInt(HAL_Handle handle) {
	HAL_Obj *obj = (HAL_Obj *) handle;
	PIE_disable(obj->pieHandle);
}

1513--1556

// Added by Dmitri Ranfft on 16.09.2015
void HAL_setupCAP(HAL_Handle handle)
{
#ifdef CAP
	HAL_Obj *obj = (HAL_Obj *) handle;
    CLK_enableEcap1Clock(obj->clkHandle);

    CAP_disableInt(obj->capHandle, CAP_Int_Type_All);    // Disable all capture interrupts
    CAP_clearInt(obj->capHandle, CAP_Int_Type_All);      // Clear all CAP interrupt flags
    CAP_disableCaptureLoad(obj->capHandle);              // Disable CAP1-CAP4 register loads
    CAP_disableTimestampCounter(obj->capHandle);         // Make sure the counter is stopped

    // Configure peripheral registers
    //CAP_setCapOneShot(obj->capHandle);                   // One-shot
    CAP_setCapContinuous(obj->capHandle);
    CAP_setStopWrap(obj->capHandle, CAP_Stop_Wrap_CEVT2);// Stop at 4 events
    CAP_setCapEvtPolarity(obj->capHandle, CAP_Event_1, CAP_Polarity_Rising);    // Falling edge
    CAP_setCapEvtPolarity(obj->capHandle, CAP_Event_2, CAP_Polarity_Falling);     // Rising edge
    //CAP_setCapEvtPolarity(obj->capHandle, CAP_Event_3, CAP_Polarity_Rising);    // Falling edge
    //CAP_setCapEvtPolarity(obj->capHandle, CAP_Event_4, CAP_Polarity_Falling);     // Rising edge

    CAP_setCapEvtReset(obj->capHandle, CAP_Event_1, CAP_Reset_Enable);   // Difference operation
    CAP_setCapEvtReset(obj->capHandle, CAP_Event_2, CAP_Reset_Enable);   // Difference operation
    //CAP_setCapEvtReset(obj->capHandle, CAP_Event_3, CAP_Reset_Enable);   // Difference operation
    //CAP_setCapEvtReset(obj->capHandle, CAP_Event_4, CAP_Reset_Enable);   // Difference operation

    CAP_enableSyncIn(obj->capHandle);                    // Enable sync in
    CAP_setSyncOut(obj->capHandle, CAP_SyncOut_SyncIn);  // Pass through

    CAP_enableCaptureLoad(obj->capHandle);

    CAP_enableTimestampCounter(obj->capHandle);          // Start Counter
    //CAP_rearm(obj->capHandle);                           // arm one-shot
    CAP_enableCaptureLoad(obj->capHandle);               // Enable CAP1-CAP4 register loads
    CAP_enableInt(obj->capHandle, CAP_Int_Type_CEVT2);   // 4 events = interrupt



    // Enable CPU INT4 which is connected to ECAP1-4 INT:
    CPU_enableInt(obj->cpuHandle, CPU_IntNumber_4);
    // Enable eCAP INTn in the PIE: Group 3 interrupt 1-6
    PIE_enableCaptureInt(obj->pieHandle);
#endif
}
hal.h

166--173

//Added by Maya
#ifdef SCI
	extern interrupt void sciaISR(void);
#endif
//Added by Dmitri Ranfft on 16.09.2015
#ifdef CAP
	extern __interrupt void ecap1ISR(void);
#endif

487--496

  //Added by Maya
#ifdef SCI
  pie->SCIRXINTA = &sciaISR;
#endif

  //Added by Dmitri Ranfft on 16.09.2015
#ifdef CAP
  pie->ECAP1_INT = &ecap1ISR;
  //PIE_registerPieIntHandler(obj->pieHandle, PIE_GroupNumber_4, PIE_SubGroupNumber_1, (intVec_t)&ecap1ISR);
#endif

1306--1333

// Added by Maya
extern HAL_Handle halHandle;
extern void HAL_setupSCI(HAL_Handle handle);
//SCIA
extern SCI_FifoStatus_e HAL_sciaGetRxFifoStatus(HAL_Handle handle);
extern void HAL_sciaWrite(HAL_Handle handle, const uint16_t data);
extern void HAL_sciaWriteMsg(HAL_Handle handle, char * msg);
extern uint16_t HAL_sciaRead(HAL_Handle handle);
extern void HAL_sciaClearRxFifoOvf(HAL_Handle handle);
extern void HAL_sciaClearRxFifoInt(HAL_Handle handle);
extern void HAL_sciaClearTxFifoInt(HAL_Handle handle);
extern void HAL_sciaEnableRxInt(HAL_Handle handle);
extern void HAL_sciaDisableRxInt(HAL_Handle handle);
extern void HAL_sciaEnableTxInt(HAL_Handle handle);
extern void HAL_sciaDisableTxInt(HAL_Handle handle);
extern bool HAL_sciaTxReady(HAL_Handle handle);
extern bool HAL_sciaTxEmpty(HAL_Handle handle);
extern bool HAL_sciaRxParityError(HAL_Handle handle);
extern bool HAL_sciaRxOverrunError(HAL_Handle handle);
extern bool HAL_sciaRxFrameError(HAL_Handle handle);
extern void HAL_sciaEnable(HAL_Handle handle);
extern void HAL_sciaDisable(HAL_Handle handle);
// Added by Maya
extern void HAL_pieAckInt(HAL_Handle handle, const PIE_GroupNumber_e groupNumber);
extern void HAL_enablePieInt(HAL_Handle handle);

// Added by Dmitri Ranfft on 16.09.2015
extern void HAL_setupCAP(HAL_Handle handle);
hal_obj.h

41--60

// drivers
#include "sw/drivers/adc/src/32b/f28x/f2802x/adc.h"
#include "sw/drivers/cap/src/32b/f28x/f2802x/cap.h" // Added by Dmitri Ranfft on 16.09.2015
#include "sw/drivers/clk/src/32b/f28x/f2802x/clk.h"
#include "sw/drivers/cpu/src/32b/f28x/f2802x/cpu.h"
#include "sw/drivers/flash/src/32b/f28x/f2802x/flash.h"
#include "sw/drivers/gpio/src/32b/f28x/f2802x/gpio.h"
#include "sw/drivers/osc/src/32b/f28x/f2802x/osc.h"
#include "sw/drivers/pie/src/32b/f28x/f2802x/pie.h"
#include "sw/drivers/pll/src/32b/f28x/f2802x/pll.h"
#include "sw/drivers/pwm/src/32b/f28x/f2802x/pwm.h"
#include "sw/drivers/pwmdac/src/32b/f28x/f2802x/pwmdac.h"
#include "sw/drivers/pwr/src/32b/f28x/f2802x/pwr.h"
#include "sw/drivers/spi/src/32b/f28x/f2802x/spi.h"
#include "sw/drivers/timer/src/32b/f28x/f2802x/timer.h"
#include "sw/drivers/wdog/src/32b/f28x/f2802x/wdog.h"
#include "sw/drivers/drvic/drv8305/src/32b/f28x/f2802x/drv8305.h"
//Added by Maya
//#include "sw/drivers/sci/src/32b/f28x/f2802x/sci.h"
#include "sci.h"

131-133

  //Added by Dmitri Ranfft on 16.09.2015
  CAP_Handle    capHandle;        //!< the eCAP handle

173

 SCI_Handle    sciaHandle;       //!< the sci handle, added by Maya

sci

sci.c

同一ファイルです。

sci.h

369--376

//Added by Maya
typedef enum
{
  SCI_RXA=0,      		//!< Denotes SCI receive A
  SCI_TXA=1,     			//!< Denotes SCI transmit A
  SCI_RXB=2,    			//!< Denotes SCI receive B
  SCI_TXB=3   			//!< Denotes SCI transmit B
} SCI_Type_e;

728--731 in static inline void SCI_write(SCI_Handle sciHandle,const uint16_t data)

  //Added by Maya
 #ifdef SCI_FIFO
   while(SCI_getTxFifoStatus(sciHandle) != 0) {};
 #endif

739--792

// Added by Maya
static inline bool SCI_txEmpty(SCI_Handle sciHandle)
{
  SCI_Obj *sci = (SCI_Obj *)sciHandle;
  bool status;

  status = (sci->SCICTL2 & SCI_SCICTL2_TXEMPTY_BITS) >> 6;

  return((bool)status);
} // end of SCI_txEmpty() function

//Added by Maya
static inline void SCI_writeMsg(SCI_Handle sciHandle, char * msg)
{
    int i;
    i = 0;
    while(msg[i] != '\0')
    {
    	SCI_write(sciHandle, msg[i]);
        i++;
    }
}

static inline bool SCI_rxParityError(SCI_Handle sciHandle)
{
  SCI_Obj *sci = (SCI_Obj *)sciHandle;
  bool status;

  status = (sci->SCIRXST & SCI_SCIRXST_PE_BITS) >> 2;

  return((bool)status);
} // end of SCI_rxParityError() function

static inline bool SCI_rxOverrunError(SCI_Handle sciHandle)
{
  SCI_Obj *sci = (SCI_Obj *)sciHandle;
  bool status;

  status = (sci->SCIRXST & SCI_SCIRXST_OE_BITS) >> 3;

  return((bool)status);
} // end of SCI_rxParityError() function

static inline bool SCI_rxFrameError(SCI_Handle sciHandle)
{
  SCI_Obj *sci = (SCI_Obj *)sciHandle;
  bool status;

  status = (sci->SCIRXST & SCI_SCIRXST_FE_BITS) >> 4;

  return((bool)status);
} // end of SCI_rxParityError() function

//End of addition by Maya

見比べる

差分の抽出が済みましたので、見比べていきましょう。
ピン変更までしてeCAPとやらを何に使っているのか、よくわかりませんね???
SCIを使うためには、基本的にMayaさんの変更箇所を見ていけばよいようです。
たかがシリアルで、こんなに面倒くさいと、このマイコン開発にリソースを割いていていいのかどうか不安になります。

動かして確認してみる

Mayaさんのコメント部分を自分のソースコードにコピーペーストし、sci.hとsci.cをプロジェクトに追加します。
また、sci.hの最初の方に

#define SCI 1

を書き加えます。

シリアル接続を確認するために、teratermでUSB COMPortに接続し、9600bpsの速度に設定します。
デバッグモードでFlashにproj_lab05b.outをアップロードすると、
"\r\n\n ********** SCI setup is done! **********\0";
の文字が表示されるはずなのですが、最初の3文字ぐらいしか出ません。

 ***9

ただ、何かは応答してくれているようです。
キーボードで文字を入力すると、エコーバックされてteraterm上に表示されます。BackSpaceキーを押すとカーソルが一つ戻ります。
Enterキーを押すと、ロックされた状態になりますが、Escを押すと、再び入力可能な状態になります。

ちゃんと動いているようですね。

FIFOを有効にして、通信欠落を減らす

sci.hのdefinesの中に
#define SCI 1
に加えて
#define SCI_FIFO 1
を追加します.

ところが、メモリの初期化がうまくいかずに起動直後はFIFOにゴミがあり、これを吐き出させる前にhal.cの中で文字列を出力させる次の2行を実行すると、わけのわからないゴミを延々と吐き続けて、クリアできないという状況に陥ります。
なので、この2行をコメントアウトします。

msg = "\r\n\n  ********** SCI setup is done! **********\0";
	SCI_writeMsg(obj->sciaHandle, msg);

sciaISRが回り始めた当初はまだゴミを少し吐くので、これを吐き出させた後に通信に使用するとうまい行くようです。
残念ながら、sci.hに定義されたどのコマンドを用いても、起動直後のバッファのゴミを削除することができませんでした。

重要な知見

LAUNCHXL-F28027F 不推奨のススメ

LAUNCHXL-F28027FにBOOSTXL-DRV8305EVM経由で電源を供給したときに、うまく初期化できません。外部リセットを行う以外の解決方法が見つかりません。
したがって、組み込み用途で使用するときに、大変不便します。

LAUNCHXL-F28027Fは、メモリ上での開発ができずコンパイルしたバイナリを毎回Flashメモリに焼きこむ必要があります。
ところが、フラッシュの耐久性の問題か、ロムライタのソフトウェアの問題か50回もしないうちに書き込み不可能になってしまいます。
書き込み不可能になったマイコンボードは捨てるしかほかありませんので、コンパイル50回毎に2000円が飛んでいくことになります。
C2000PiccoloシリーズおよびInstaSPINは、かなり特殊なソフトウェア体系(整理されてない)ので、ある程度使えるエキスパートになるまでには相当な時間がかかります。

同じシリーズの上位機種LAUNCHXL-F28069Mはとりあえずこれらの問題はありませんので、サイズはデカいですが値段はあまり変わらないのでこちらを推奨します。

SCI受信割り込み(例えば、SCIRXINTに紐づけられたsciaISR)の中で一文字たりとも送信してはいけない

まれにモータの制御が飛び一瞬停止するなど異常動作を起こすので、大暴走して事故の原因になりかねません。
本来、SCITXINTを有効にして、適切な送信割り込みを掛けるべきなのだと思いますが、すると今度はモータ制御がうまく行かなくなります。まだ原因が特定できません。
main関数のforeverループの中でループ一回に一文字づつ送るなどの方が無難なようです。mainISRではありません。mainISRは、adcの割り込みの呼び出し先です。
文字列長など、セグメンテーションエラーを起こさないように十分留意してください。

//Added by Maya
#ifdef SCI

interrupt void sciaISR(void) {
	//RXISRCount++;

	ReceivedChar = HAL_sciaRead(halHandle) & 0x00FF;

	//Handling escape.
	if(ReceivedChar != 27){
		//Handling carriage return/new line.
		if(ReceivedChar != '\r' && ReceivedChar != '\n' && cmdReady == 0){
			//Show input.
			if(ECHO_ON){
				// \HAL_sciaWrite(halHandle, ReceivedChar); ///// Caution! Danger!
			}
			//Handling backspace/delete.
			if(ReceivedChar != 127 && ReceivedChar != 8){
				bufPos++;
				//If the end of the buffer wasn't reached, add new char to the buffer.
				if(bufPos < BUF_LEN){
					cmdBuf[bufPos-1] = (char)ReceivedChar; //Adding char.
					cmdBuf[bufPos] = '\0'; //Appending null to indicate the end of the string.
				}
			}else{
				//If the beginning of the buffer wasn't reached, remove the previous char from the buffer.
				if(bufPos > 0){
					bufPos--;
					//Only delete if within buffer range.
					if(bufPos < BUF_LEN){
						cmdBuf[bufPos] = '\0';
					}
				}
			}
		}else if(cmdReady == 0){ //If enter was pressed, start new line and set cmdReady flag.
			msg = "\n\r";
			// HAL_sciaWriteMsg(halHandle, msg); ///// Caution! Danger!
			cmdReady = 1;
		}
	}else{ //If escape is pressed, reset command buffer and clear cmdReady flag.
		cmdReady = 0;
		bufPos = 0;
		cmdBuf[0] = '\0';
	}

	HAL_sciaClearRxFifoOvf(halHandle);
	HAL_sciaClearRxFifoInt(halHandle);

	HAL_pieAckInt(halHandle,PIE_GroupNumber_9);		// Issue PIE ack INT9

	return;
}

#endif

今日の友達がいない漫画

タイトルに反して、主人公湯神くんの周りには登場人物多い。

特性の分からない3相DCブラシレスモーターをソフトウェアエンコーダを搭載したTiのマイコンボードLAUNCHXL-F28069MとモータドライバBOOSTXL-DRV8305EVMを使って動かす(その5)

(編集中)
簡単に実験できるように、アナログスイッチやボリュームでモータを制御できると便利です。
Tiのデータシートを参考に、DRV8305EVM用のアナログコントローラを設計してみます。

1.ハードウェアの設計と製作

f:id:cvl-robot:20161019143057p:plain
できました、これです。

速度指令値と加速度指令値用にボリュームを2つ、回転方向指示用にスイッチを1つ、予備用にもうひとつスイッチ、Fault表示用にLEDを一つ、付けます。
マイコンボードのデータシートと、ドライバーボードのデータシートを見比べて、ドライバーボード側で使っていないピンを探します。
f:id:cvl-robot:20161019143355p:plain
ボリューム用にADC入力のピンが2つ必要ですので探していくと、ADCINA6とADCINB6がギリギリ空いていました。
同様にスイッチ用のGPIOピンを探していくと、P12とP22がかろうじて空いていました。(!)は、クイックスタートガイドのPDFによると,「割り込み能力があるI/Oピンを意味します。」だそうです。
マイコンの3.3VピンからLEDを直接駆動するほどの電流を引くのは難しいようなので、74HC245をバッファ代わりに挿入します。

マイコンボードには多種多様なインターフェースピンが用意されているものの、そのほとんどをドライバーボードが占有してしまうのでユーザが使えるのは極一部なのですね。
簡単な部品しかないので基板は簡単に作ることができると思います。
20ピンフラットケーブル等でBOOSTXL-DRV8305EVMのJ1側の端子に接続します。

また、実験用には、電圧計と電流計が付いていて、スイッチをすぐ切ることができる、十分な電流容量を持った電源装置があると便利です。
モーターIDに失敗すると、モーターは回らないまま異音を上げて大電流が流れるなんて言う事態に、よくなります。

LAUNCHXL-F28027FとBOOSTXL-DRV8305EVMのピンも確認しておきます。
f:id:cvl-robot:20161020152238p:plain
ピン配置はAIO2を除けばだいたい同じです。ただ、ピン番号は全然違いますので、名前を調整する必要があります。

2.ソフトウェアの改造

proj_lab03bを基に、ソフトウェアの改造を行っていきます。

手元に用意するべき資料は2つあり
・TMS320C2000:Piccolo MCUのソフトウェア開発入門
・MotorWare Software Architecture
です。前者はWEBから、後者はMotorWareのアプリケーションから入手できます。

ADCの取り扱いはこの資料も有用です。
http://www.tij.co.jp/jp/lit/ug/jaju167/jaju167.pdf

[追記]
ピン配置の見比べが超絶面倒くさいです。
F28027F
f:id:cvl-robot:20161219215744p:plain
F28069M
f:id:cvl-robot:20161219215750p:plain
f:id:cvl-robot:20161219215753p:plain

メモ:HiRes時代の自作オーディオ その2:2016年10月ベストチョイス編

もし今、自分がオーディオシステムを組むなら、これをチョイス。
パワーアンプはNCore400、プリ代わりのDACはTerra-Berry。

NC400 mono kit

1台650ユーロでモノなので、2台分で1300ユーロ。およそ15万円。
www.hypexshop.com

Marantz MA-10

BTL 2chなので、中身にNCoreを4枚使っています。
www.marantz.jp

Terra-Berry

I2S入力のDAC。27,000円(税込み)。入力インターフェースは別途用意する必要がある。バランスケーブルが必要になります.
RaspberryPi Terra-Berry - テラテクノス株式会社

USB入力にしたいので、Amanero社のCombo384を選択.\12,800-
www.amanero.com

ここまで小計\189,800-。安くはないですが、きっと最高。
スピーカーはJBLの38口径のウーハーを積んだ43シリーズが良いなぁー。

追記:2017/10/27

SonarWorks Reference 3 Complete with Mic

汎用のオーディオ出力の補正にも使える音響補正ソフトウェアが来ました!
現在の最新版は、Reference 4! 製品準備中のようです。

今日のおとうふ

Aiの遺伝子の著者山田胡瓜先生がTwitterで絶賛していた漫画。必死に何もしません。

ICP(Iterative Closest Point)法を勉強したいときのメモ

(編集中)

広島大学玉木先生のスライド

sssslide.com

かみやんさんの『Efficient Variants of the ICP Algorithm』(サーベイ論文)の解説

d.hatena.ne.jp

SparseICP(c++ソースコード、提案手法の比較用にオーソドックスな方のソースもある)

github.com
Windowsでビルドしたい場合は、同梱のEigenが古くてエラーを起こすので、最新版で上書きすること。

最終頁と上記ソースコードを見比べると、理解が早い

https://igl.ethz.ch/projects/ARAP/svd_rot.pdf

コンピュータビジョン 最先端ガイド3

増田先生の第2章にcソースコードもある.

コンピュータビジョン最先端ガイド 3 (CVIMチュートリアルシリーズ)

コンピュータビジョン最先端ガイド 3 (CVIMチュートリアルシリーズ)

MotorwareのGUI Composerの起動が面倒くさいことの対処

MotorWareのExampleの実行方法は二つあります。
1. コンパイル出力(proj_lab02b.out)をappProgram.outと改名してGUI Composerの実行ファイルと同じフォルダにコピーしてGUIを起動する方法
2. IDE(Code Composer Studio)にGUI Composerをzip化して読み込ませてDebugモードでoutファイルを読み込んで起動する方法

そのままでは、どっちも超絶面倒くさいです。
お勧めは、1の方法に簡単なバッチファイルを書いて、半自動で起動できるようにしておく方法です。

例えば、次のようなファイルをコンパイル出力先のフォルダに作ります。

proj_lab02b.bat

copy proj_lab02b.out "C:\ti\guicomposer\webapps\InstaSPIN_F2802xF_UNIVERSAL\appProgram.out"
cd "C:\ti\guicomposer\webapps\InstaSPIN_F2802xF_UNIVERSAL\"
InstaSPIN_UNIVERSAL.exe

特性の分からない3相DCブラシレスモーターをソフトウェアエンコーダを搭載したTiのマイコンボードLAUNCHXL-F28069MとモータドライバBOOSTXL-DRV8305EVMを使って動かす(その4)

(編集中)
最重要ファイルであるところのmotorware_selecting_user_variables.xlsxのv2p1 2014-May-28版を見てみましょう。
MotorwareのResources->Training: User's Guides, Labs, Tutorials->InstaSPIN Projects Setting User Variablesの下にあります。

1. FILL IN THESE VALUES FOR YOUR USER.H, MOTOR, and INVERTER HW

(お使いのuser.h, モータ,インバータハードウェアに合わせて、これらの値を埋めてください。)

USER_SYSTEM_FREQ_MHz90[MHz]
Maximum Bus Voltage24[V]
Maximum Target RPM40000[RPM]
USER_MOTOR_NUM_POLE_PAIRS2[PAIRS]
USER_PWM_FREQ_kHz45[kHz]
USER_NUM_PWM_TICKS_PER_ISR_TICK3[ticks]
USER_NUM_ISR_TICKS_PER_CTRL_TICK1[ticks]
USER_NUM_CTRL_TICKS_PER_CURRENT_TICK1[ticks]
USER_NUM_CTRL_TICKS_PER_EST_TICK1[ticks]
USER_ZEROSPEEDLIMIT0.002

sub-calculations:
Target Hz = (Maximum Target RPM) * (USER_MOTOR_NUM_POLE_PAIRS) / 60
POLE = 2 * (USER_MOTOR_NUM_POLE_PAIRS)
ISR_Hz = (USER_PWM_FREQ_Hz) / (USER_NUM_PWM_TICKS_PER_ISR_TICK)
CTRL_Hz = (ISR_Hz) / (USER_NUM_ISR_TICKS_PER_CTRL_TICK)
CURRENT_Hz = (CTRL_Hz) / (USER_NUM_CTRL_TICKS_PER_CURRENT_TICK)
EST_Hz = (CURRENT_Hz) / (USER_NUM_CTRL_TICKS_PER_EST_TICK)

2. The following are set by HW design, use defaults for TI EVM or your own HW

(次の値はハードウェアデザインによって決定されますので,Tiの評価ボードまたはお使いのハードウェアのための規定値をお使いください。)

USER_VOLTAGE_FILTER_POLE_Hz364.682[Hz]
USER_ADC_FULL_SCALE_CURRENT_A33.00[A]
USER_ADC_FULL_SCALE_VOLTAGE_V26.3147[V]

3. THESE VALUES ARE RECOMMENDED FOR USE once TRUE checks are satisfied

 (TRUEの確認が満たされると,これらの値は使用できます。)

Ideal USER_IQ_FULL_SCALE_FREQ_Hz for Motor

(モータのための理想的なUSER_IQ_FULL_SCALER_FREQ_Hz)
Target Hz with 10% buffer
(10%の余裕を加えた目標周波数)

Maximum allowed USER_IQ_FULL_SCALE_FREQ_HZ for HW

(ハードウェアのための最大許容可能なUSER_IQ_FULL_SCALE_FREQ_HZ)
4 * USER_VOLTAGE_FILTER_POLE_Hz [with 5% buffer]
(USER_VOLTAGE_FILTER_POLE_Hzの4倍から5%の余裕を持たせた値)

USER_IQ_FULL_SCALE_FREQ_Hz

Lower of Ideal and Maximum
(理想と最大のうち小さい方)

Maximum RPM Supported

(サポートされる最大回転数)
Rotor Hz can be 1.98 * USER_IQ_FULL_SCALE_FREQ_HZ; EST speed will roll-over outside boundary!!!!
(ローターの周波数はUSER_IQ_FULL_SCALE_FREQ_Hzの1.98倍を取り得るため,推定速度は境界の外に転がり出得ます。)

USER_MOTOR_FLUX_EST_FREQ_Hz

5-150 Hz; ~10% of Maximum Target Hz but use low as possible where Ls and Flux can be ID'd consistently
(5-150Hz; 最大目標周波数のおよそ10%、ただしLsとFluxが一貫して特定できる範囲で出来るだけ低い値を使ってください。)

USER_MAX_ACCEL_EST_Hzps

If USER_MOTOR_FLUX_EST_FREQ_Hz > 50 Hz must increase the acceleration during ID to avoid a timeout
(もしUSER_MOTOR_FLUX_EST_FREQ_Hzが50Hzよりも大きければ,タイムアウトを避けるためにIDの間の加速を増加してください。)

CURRENT Hz > MAX_Hz * 7

If FALSE increase CURRENT kHz or reduce MAX_HZ; Standard good practice for control systems
(もしFALSEならばCURRENT kHzを増加させるか、MAX_Hzを現象させてください。制御システムのための標準的な良い慣習値)

EST <= CTRL

If FALSE correct; No need to run the estimator if results are not being updated in control loop
(もしFALSEならば、制御ループ中に更新され無いことを意味するので、推定は実行されません。)

EST > 10 * USER_VOLTAGE_FILTER_POLE_Hz (+10% margin)

If FALSE increase EST Rate
(もしFALSEならEST Rateを増やしてください。)

EST > 8 * TARGET_Hz

If FALSE, increase effective EST Frequency using TICKs
(もしFALSEなら、TICKsを使って有効なEST周波数に増加さえてください。)

FLUX_EST_FREQ > ZEROSPEEDLIMIT * FULL_SCALE_FREQ

If FALSE, lower ZEROSPEEDLIMIT
(もしFLASEならば, ZEROSPEEDLIMITを減らしてください。)

USER_IQ_FULL_SCALE_CURRENT_A

Slightly >= 0.5 * ADC_FULL_SCALE_CURRENT_A
(0.5*ADC_FUKK_SCALE_CURRENT_Aよりわずかに大きい値にしてください。)

starting USER_IQ_FULL_SCALE_VOLTAGE_V

 Initially set to bus voltage until flux is identified
(磁束が特定されるまで最初に設定されるバス電圧値)

4. Once Motor ID is attempted, update these as best you can and check IQ_V Scaling

 (モーター特定を実行したら,これらの値を出来るだけ最適に調整して、IQ_Vの値幅を確認してください。)

USER_MOTOR_RATED_FLUX0.023[V/Hz]
USER_MOTOR_Ls_d0.00005[H]

sub-calculations:
Minumiu Flux Measurement = (new USER_IQ_FULL_SCALE_VOLTAGE_V) / (EST_Hz * 1000) / 0.7
= Minimum Flux that can be measured with new USER_IQ_FULL_SCALE_VOLTAGE_V (cell I20)
(=最小磁束はnew_USER_IQ_FULL_SCALE_VOLTAGE_Vで計ることができます。)

4. Check after valid USER_MOTOR_RATED_FLUX Identification
(有効なUSER_MOTOR_RATED_FLUX特定後の確認)

Minimum Flux Measurement < 0.9 * RATED_FLUX

(最小磁束測定値が0.9*RATED_FLUXより小さいこと。)
  If FALSE, reduce new USER_IQ_FULL_SCALE_VOLTAGE as low as Bus Voltage / 2 + 10% buffer
(もしFALSEならば,new USER_IQ_FULL_SCALE_VOLTAGEを電源電圧の半分に10%の余裕を持たせた値よりも小さくしてください。)

IQ_VOLTAGE < RATED_FLUX * EST Hz

If FALSE, reduce new USER_IQ_FULL_SCALE_VOLTAGE or increase EST_Hz
(もしFALSEならば、new USER_IQ_FULL_SCALE_VOLTAGEを減らすか、EST_Hzを増やしてください。)

new USER_IQ_FULL_SCALE_VOLTAGE_V

Use larger of a) or b). Minimum of Bus Voltage / 2 + 10% buffer if required to make I18 & I19 TRUE
(a)またはb)の大きな方を使ってください。Minimum Flux Measurement < 0.9 * RATED_FLUXとIQ_VOLTAGE < RATED_FLUX * EST_Hzの条件を満たすためには、電源電圧の半分に10%の余裕を持たせた値にしてください。
a) Bus Voltage
(電源電圧)
Typical Minimum, but can reduce as low as Bus Voltage / 2 + 10% buffer
(形式上の最小値、ただしBus Voltageの半分に10%の余裕を持たせた電圧程度まで減りえます。)
b) Bemf Generated @ Target Hz + 10% buffer
(目標周波数+10%余裕における逆起電力)

5. Ideal Pole Design when you build wwn HW

(ユーザが自身のHWを作る際の理想的な極設計)

Minimum Pole200[Hz MIN]
Ideal* Pole >=366.667[Hz]
Half** Pole >=183.3333[Hz]

* Use Ideal pole to keep Target Hz < USER_IQ_FULL_SCALE_FREQ_Hz but note that as pole Hz increases you are more susceptible to drift/error and should use higher precision Vph filter Capacitors
(理想的な極を使うためにTarget Hz < USER_IQ_FULL_SCALE_FREQ_Hzを維持してください。しかし,極周波数の増加は、ドリフトやエラーに影響されやすくするので高い精度のVphフィルタキャパシタを使うように、気を付けてください。)

** You may use a lower pole (down to half the value of the ideal) that is less sensitive to capacitor error/offset/drift. Set USER_IQ_FULL_SCALE_FREQ_HZ <= 4 * Lowered Pole * 0.95 buffer. Target Hz can reach +/- 1.98 * USER_IQ_FULL_SCALE_FREQ_Hz

Performance difference between the two is typically very marginal though. Do NOT use a filter pole < Minimum Pole!!!

user.hへの反映

マイコンボードとインバータボードに依存して、テンプレートのuser.hが用意されています。たとえば、LAUNCHXL-F28027F+BOOSTXL-DRV8305EVMの組み合わせの場合は、

C:\ti\motorware\motorware_1_01_00_16\sw\solutions\instaspin_foc\boards\boostxldrv8305_revA\f28x\f2802xF\src

にあります。この中から、編集可能な値をピックアップしてみます。

CURRENTS AND VOLTAGES

#define USER_IQ_FULL_SCALE_FREQ_Hz (800.0) // 800 Example with buffer for 8-pole 6 KRPM motor to be run to 10 KRPM with field weakening; Hz =(RPM * Poles) / 120
#define USER_IQ_FULL_SCALE_VOLTAGE_V (24.0) // 24.0 Set to Vbus
#define USER_ADC_FULL_SCALE_VOLTAGE_V (44.30) // BOOSTXL-DRV8305EVM = 44.30 V
#define USER_IQ_FULL_SCALE_CURRENT_A (24.0) // BOOSTXL-DRV8305EVM = 24.0 A
#define USER_ADC_FULL_SCALE_CURRENT_A (47.14) // BOOSTXL-DRV8305EVM = 47.14 A
#define USER_NUM_CURRENT_SENSORS (3) // 3 Preferred setting for best performance across full speed range, allows for 100% duty cycle
#define USER_NUM_VOLTAGE_SENSORS (3) // 3 Required
#define I_A_offset (1.210729778) // BOOSTXL-DRV8305EVM = 1.047175646
#define I_B_offset (1.209441483) // BOOSTXL-DRV8305EVM = 1.044038892
#define I_C_offset (1.209092796) // BOOSTXL-DRV8305EVM = 1.040363491
#define V_A_offset (0.5084558129) // BOOSTXL-DRV8305EVM = 0.5256254077
#define V_B_offset (0.5074239969) // BOOSTXL-DRV8305EVM = 0.5250559449
#define V_C_offset (0.5065535307) // BOOSTXL-DRV8305EVM = 0.5247237682

CLOCKS & TIMERS

#define USER_SYSTEM_FREQ_MHz (60.0)
#define USER_PWM_FREQ_kHz (45.0) //30.0 Example, 8.0 - 30.0 KHz typical; 45-80 KHz may be required for very low inductance, high speed motors
#define USER_MAX_VS_MAG_PU (0.5) // Set to 0.5 if a current reconstruction technique is not used. Look at the module svgen_current in lab10a-x for more info.
#define USER_EST_HANDLE_ADDRESS (0x600)
#define USER_VD_SF (0.95)

DECIMATION

#define USER_NUM_PWM_TICKS_PER_ISR_TICK (3)
#define USER_NUM_ISR_TICKS_PER_CTRL_TICK (1) // 2 Example, controller clock rate (CTRL) runs at PWM / 2; ex 30 KHz PWM, 15 KHz control
#define USER_NUM_CTRL_TICKS_PER_CURRENT_TICK (1) // 1 Typical, Forward FOC current controller (Iq/Id/IPARK/SVPWM) runs at same rate as CTRL.
#define USER_NUM_CTRL_TICKS_PER_EST_TICK (1) // 1 Typical, FAST estimator runs at same rate as CTRL;
#define USER_NUM_CTRL_TICKS_PER_SPEED_TICK (15) // 15 Typical to match PWM, ex: 15KHz PWM, controller, and current loop, 1KHz speed loop
#define USER_NUM_CTRL_TICKS_PER_TRAJ_TICK (15) // 15 Typical to match PWM, ex: 10KHz controller & current loop, 1KHz speed loop, 1 KHz Trajectory

LIMITS

#define USER_ZEROSPEEDLIMIT (0.5 / USER_IQ_FULL_SCALE_FREQ_Hz) // 0.002 pu, 1-5 Hz typical; Hz = USER_ZEROSPEEDLIMIT * USER_IQ_FULL_SCALE_FREQ_Hz
#define USER_MAX_ACCEL_Hzps (20.0) // 20.0 Default
#define USER_MAX_ACCEL_EST_Hzps (5.0) // 5.0 Default, don't change
#define USER_IDRATED_FRACTION_FOR_L_IDENT (1.0) // 1.0 Default, don't change
#define USER_IDRATED_DELTA (0.00002)
#define USER_SPEEDMAX_FRACTION_FOR_L_IDENT (1.0) // 1.0 Default, don't change
#define USER_FLUX_FRACTION (1.0) // 1.0 Default, don't change
#define USER_POWERWARP_GAIN (1.0) // 1.0 Default, don't change
#define USER_R_OVER_L_EST_FREQ_Hz (300) // 300 Default for high speed motors, can reduce to 100 if RoverL from Motor ID is < 2000

POLES

#define USER_VOLTAGE_FILTER_POLE_Hz (344.62) // BOOSTXL-DRV8305 = 344.62 Hz
#define USER_OFFSET_POLE_rps (20.0) // 20.0 Default, do not change
#define USER_FLUX_POLE_rps (100.0) // 100.0 Default, do not change
#define USER_DIRECTION_POLE_rps (6.0) // 6.0 Default, do not change
#define USER_SPEED_POLE_rps (100.0) // 100.0 Default, do not change
#define USER_DCBUS_POLE_rps (100.0) // 100.0 Default, do not change
#define USER_EST_KAPPAQ (1.5) // 1.5 Default, do not change

Define each motor with a unique name and ID number

#define Anaheim_BLY172S 102
#define USER_MOTOR Anaheim_BLY172S

#define USER_MOTOR_TYPE MOTOR_Type_Pm // Motor_Type_Pm (All Synchronous: BLDC, PMSM, SMPM, IPM) or Motor_Type_Induction (Asynchronous ACI)
#define USER_MOTOR_NUM_POLE_PAIRS (4) // PAIRS, not total poles. Used to calculate user RPM from rotor Hz only
#define USER_MOTOR_Rr (NULL) // Induction motors only, else NULL
#define USER_MOTOR_Rs (0.3968007) // Identified phase to neutral resistance in a Y equivalent circuit (Ohms, float)
#define USER_MOTOR_Ls_d (0.0006708066) // For PM, Identified average stator inductance (Henry, float)
#define USER_MOTOR_Ls_q (0.0006708066) // For PM, Identified average stator inductance (Henry, float)
#define USER_MOTOR_RATED_FLUX (0.03433958) // Identified TOTAL flux linkage between the rotor and the stator (V/Hz)
#define USER_MOTOR_MAGNETIZING_CURRENT (NULL) // Induction motors only, else NULL
#define USER_MOTOR_RES_EST_CURRENT (1.0) // During Motor ID, maximum current (Amperes, float) used for Rs estimation, 10-20% rated current
#define USER_MOTOR_IND_EST_CURRENT (-1.0) // During Motor ID, maximum current (negative Amperes, float) used for Ls estimation, use just enough to enable rotation
#define USER_MOTOR_MAX_CURRENT (5.0) // CRITICAL: Used during ID and run-time, sets a limit on the maximum current command output of the pded Speed PI Controller to the Iq controller
#define USER_MOTOR_FLUX_EST_FREQ_Hz (20.0) // During Motor ID, maximum commanded speed (Hz, float), ~10% rated

user.hとmotorware_selecting_user_variables.xlsxを並べて開いて、データを相互に編集してやる必要があります。
1.最初に、user.hからエクセルの黄色い枠の中にデータをコピペしていきます。モニターで黄色が見にくいのでこのページでは、赤になっています。
2.次に、エクセルの緑の枠の値をuser.hにコピーして持ってきます。USER_MAX_ACCEL_EST_Hzpsは変えるな、とuser.hに書いてあるので変えない方が良いでしょう。
3.実機でモータ同定を行ってから、両方の青枠のデータを更新します。モータ同定はうまくいかないことの方が多いので、うまく回るかどうかを確認してから反映してください。
4.水色で示したモータの巻き線抵抗や、インバータの電流電圧検出抵抗の値をuser.hに更新します。

Tiのホームページの素晴らしい宣伝文句とは裏腹に、おしゃれなGUIなどでは設定できませんので、エディタ等でテキストベースで設定を書き換えます。
(ここまで出来ていて、何故自動ソフトウェア化しないのだろう??)

実際のパラメータ決定法

上記の計算結果をuser.hに入れて、コンパイルして、実行しようとしてもまずうまくいきません。
USER_MOTOR_RATED_FLUXの値が下限リミットに引っかかってしまい、エラーで弾かれるか、まともに動かないという結果になりがちです。
解決方法としては、excelのUSER_MOTOR_RATED_FLUXを使わない、というのが本末転倒ですが現実的なようです。

GUI ComposerのInstaSPIN-FOC MotorWare Instrumentationタブの右下の方に、Variable Overflow Checksがあり、この中の

Flux * Full Scale Freq [V] <

の項目がうまく設定できているかどうかのカギです。
要するに、この項目が下限電圧値を示していてFull Scale Freqの値はエクセルシート上ですでに計算していますから、Fluxの値をこれから直接計算してしまいましょう。
下限電圧値は、「電源電圧の半分に10%の余裕を持たせた値」としていますので、バス電圧が24Vの場合

24[V]/2*1.1=13.2[V]

です。
USER_IQ_FULL_SCALE_FREQ_Hzはエクセルシートの右側で、例えば800Hzとか513.3Hzなんていうオーダーの数値になっています。
試しに513.3Hzとすると、

Flux = 13.2[V] / 513.3[Hz] = 0.02571596 [V/Hz]

となります。エクセルと10倍程度違ったり、自動同定で見つけさせた値とかけ離れていたりしますが、こちらの値の方が上手くいくことが多いです。

これが、InstaSPIN-MOTION用だとまた少し違う項目が出てきます。が、それはまた次に。


[1]parameter settings: http://www.ti.com/lit/ug/spruhj1f/spruhj1f.pdf

特性の分からない3相DCブラシレスモーターをソフトウェアエンコーダを搭載したTiのマイコンボードLAUNCHXL-F28069MとモータドライバBOOSTXL-DRV8305EVMを使って動かす(その3)

Tiの製品はドキュメントが多いのはいいのですが、煩雑であまり整理されているようには見えません。
また、独自用語や独自製品名、独自技術名に変な名前を付けるのが好きで、ある程度一般的な技術知識を持ってる人が見ても、ちんぷんかんぷんな言葉が散見されます。
さらに、日本語訳されているドキュメントもあるにはあるのですが、途中で力尽きたのか触りの部分だけ翻訳されていたり、古いままだったりします。
なので、読むときには必ず英語ドキュメントと見比べるなど注意が必要です。

ここでは、資料と用語の簡単なまとめをしておきたいと思います。

資料の入手先

1. MotorWare

www.tij.co.jp
最初にこれをインストールします。
exe形式のアプリケーションなのですが、実態は技術資料のリンク集と、マイコンやインバータボード毎にまとめられたソフトウェアdriverやexampleのソースコード集です。
まず、これをインストールしておけば、だいたいの資料へのポインタはわかるようになります。
標準のインストール先は、c:\ti\motorwareの下になります。

*1

ちなみに、Motorwareと同様にTiのマイコン一般用のリソースをまとめたControlSuiteというアプリがありますが、モーター制御を主眼に置いて使用するなら不要です。シリアル通信のソースコードを参照する等、参考程度に使用してください。

起動すると、このようなリストが出ます。
f:id:cvl-robot:20161007151012p:plain

開発環境のインストール

最初にするべきことは、一番下のCCSのダウンロードとインストールです。
CCSはCode Composer Studioの略で、EclipseベースのTi C2000マイコン用の開発IDEです。
有料版と無料版がありますが、無料版でOKです。
ダウンロードには、ユーザー登録と用途の申請が必要になります。
こちらも標準のインストール先は、c:\tiの下になります。

開発資料の確認

MotorwareのResourcesを展開すると、
f:id:cvl-robot:20161007151720p:plain
このようなリストが出てきます。
見るべきところをさらに展開すると、
f:id:cvl-robot:20161007151940p:plain
このようになります。
マイコンボードF28069Mのハードウェアに関する情報と、
・インバータDRVV8305EVMについてのハードウェア情報と、
・Tiのマイコンシリーズ共通の技術情報、
・ユーザーガイドやチュートリアル
です。

2. C2000 Piccoloシリーズの開発入門

http://www.tij.co.jp/jp/lit/an/jaja230a/jaja230a.pdf
日本語で書かれた有用な資料ですが、翻訳が古く現在のバージョンでは致命的な問題がありますので、4章は絶対に読まないでください。
現在のバージョンでは、Flashへの書き込みはCCSの上だけでExampleのソース変更も不要でもっと簡単にできるようになっています。

固定小数点

c2000シリーズの多くは浮動小数点演算機能を持たず、あまり使い慣れない固定小数点で計算する必要があります。
IQmathライブラリという名前の固有小数点演算ライブラリが提供されており、一手間多くはなりますが慣れれば普通に計算できるようになります。

ADC

多チャンネルの入力を切り替えて使うタイプのADCで、タイミングや順序など細かい設定をプログラミングできるようになっています。
しかし、使い慣れない感じのAPIなので資料を読んでおくと有益です。

SCI(UART)

RS232で知られるいわゆるUARTシリアル接続は、TIのマイコンではSCIと呼ばれます。
これも少し煩雑なので、読んでおいた方が良いです。

用語のメモ

TRM(Technical Reference Manual)のSoftware Architectureの最初の方に記述があります。

APIApplication Programming Interface
ACIM – Alternating Current Induction Motor
ADC – Analog-to-Digital Converter
ePWM – Enhanced Pulse Width Modular
FIFO – First In, First Out
GUI – Graphical User Interface
HAL – Hardware Abstraction Layer
IDE – Integrated Development Environment
ISR – Interrupt Service Routine
MCU – Micro-Controller Unit
PIE – Peripheral Interrupt Expansion
PWM – Pulse Width Modulation
PMSM – Permanent Magnet Synchronous Motor
RAM – Random Access Memory
ROM – Read Only Memory
RTOS – Real Time Operating System
SOC – Start Of Conversion

Piccolo F2806xM InstaSPIN-MOTION TRMの54ページに記述があります。

ACIM — Alternating current induction motor. (交流誘導電動機, 交流誘導モーター)
ADRC — Active Disturbance Rejection Control. (自動外乱排除制御) Estimates and compensates for system disturbance, in real-time. (実時間での、システム外乱の推定と補償)
CCStudio — Code Composer Studio. (コードコンポーザースタジオ、開発環境)
FAST — Unified observer structure which exploits the similarities between all motors that use magnetic flux for energy transduction (磁束エネルギー伝達を使うすべてのモータの類似性を利用した統一オブザーバ機構), automatically identifying required motor parameters and providing the following motor feedback signals: (必要なモータパラメータの自動推定と以下のモーターフィードバック信号)
• High-quality Flux signal for stable flux monitoring and field weakening. (安定な磁束観測と弱め界磁のための高品質な磁束信号)
• Superior rotor flux Angle estimation accuracy over wider speed range compared to traditional observer techniques independent of all rotor parameters for ACIM.
• Real-time low-noise motor shaft Speed signal.
• Accurate high bandwidth Torque signal for load monitoring and imbalance detection.
FOC — Field-oriented control.
Forced-Angle — Used for 100% torque at start-up until the FAST rotor flux angle tracker converges within first electrical cycle.
InstaSPIN-FOC — Complete sensorless FOC solution provided by TI on-chip in ROM on select devices (FAST observer, FOC, speed and current loops), efficiently controlling your motor without the use of any mechanical rotor sensors.
InstaSPIN-MOTION — A comprehensive motor-, motion- and speed-control software solution that delivers robust system performance at the highest efficiency for motor applications that operate in various motion state transitions. InstaSPIN-MOTION builds on and includes InstaSPIN-FOC, combined with SpinTAC™ Motion Control Suite from LineStream Technologies.
IPM — Interior permanent magnet motor.
LineStream Technologies — Pioneers in the world of embedded controls software. Boasting a team of motor control experts from six different countries cumulatively speaking fifteen languages and possessing over eighty years of industry experience, LineStream is fast becoming the world's preeminent stronghold of embedded motor control knowledge.
Motor Parameters ID or Motor Identification — A feature added to InstaSPIN-FOC, providing a tool to the user so that there is no barrier between running a motor to its highest performance even though the motor parameters are unknown.
PI — Proportional-integral regulator.
PMSM — Permanent magnet synchronous motor.
PowerWarp™ — Mode of operation used for AC induction motors (ACIM) that allows minimum current consumption.
Rs-Offline Recalibration — InstaSPIN-FOC feature that is used to recalibrate the stator resistance, Rs, when the motor is not running.
Rs-Online Recalibration — InstaSPIN-FOC feature that is used to recalibrate the stator resistance, Rs, while the motor is running in closed loop.
SpinTAC™ Motion Control Suite — Includes and advanced speed controller, a motion engine, and a motion sequence planner. The SpinTAC disturbance-rejecting speed controller proactively estimates and compensates for system disturbances in real-time, improving overall product performance. The SpinTAC motion engine calculates the ideal reference signal (with feed forward) based on user-defined parameters. SpinTAC supports standard industry curves, and LineStream’s proprietary "smooth trajectory" curve. The SpinTAC motion sequence planner operates userdefined state transition maps, making it easy to design complex motion sequences.
SVM — Space-vector modulation. (空間ベクトル変調)

あ、別にTiの製品の売り込みをしたいわけではないので、このページは機能や利点の紹介はしません。
自分で使うのに必要な情報を整理していきたいだけです。

今日の沼津漫画

GTRomanをはじめとする西風先生の漫画全般、おおよそ全部沼津です。愛にあふれていて超オススメ。ドラマ化されないかなー。
旧版 

GTロマン 1 (ヤングジャンプコミックス)

GTロマン 1 (ヤングジャンプコミックス)

完全版 
西風special selection GT roman完全版 1 (SPコミックス)

西風special selection GT roman完全版 1 (SPコミックス)

Kindle版 
GT Roman(1)

GT Roman(1)

ストラダーレムック版 
GT roman STRADALE 1 (GTロマン ストラダーレ 1) (Motor Magazine Mook)

GT roman STRADALE 1 (GTロマン ストラダーレ 1) (Motor Magazine Mook)

ストラダーレコミック版 
GT roman STRADALE SPECIALE (SPコミックス)

GT roman STRADALE SPECIALE (SPコミックス)

全部買うと良いです。

夏草冬涛 (上) (新潮文庫)

夏草冬涛 (上) (新潮文庫)

夏草冬涛 (下) (新潮文庫)

夏草冬涛 (下) (新潮文庫)

*1:英語のページでは、MotorWare™ is a cohesive set of software and technical resources for developing InstaSPI-FOC™ and InstaSPIN-MOTION™ based applications.これを直訳すると「モータウェアはInstaSPIN-FOCとInstaSPIN-MOTIONに基づくアプリケーションを開発するためのソフトウェアと技術資料をまとめたセットです。」と、ちゃんと書いてあるのですが、Tiの日本語のページには、「Piccolo InstaSPIN-FOC ソフトウェア・ィストリビューションは、C 言語、オブジェクト指向で、かつ API ベースの新しいモーター制御ライブラリ(モジュール、ドライバ、システム例、資料)を使用することで、開発を容易に、評価を迅速に実行。」とあります。機械翻訳なのかよほど日本語ができないのか、一事が万事こんな感じで酷い。