레이블이 stm32인 게시물을 표시합니다. 모든 게시물 표시
레이블이 stm32인 게시물을 표시합니다. 모든 게시물 표시

2014/12/04

STM32에 MCX314AL을 붙여보자 -- 5. TMC2660 굴려먹기

이젠 Bipolar 스텝모터 드라이버(TMC2660)를 돌려보자.

회로 설계할때 읽어봐서 스펙을 다 까먹었으니까 다시 확인해보자.


Features and Benefits

- Drive Capability up to 4A motor current
- Voltage up to 30V DC
- Highest Resolution up to 256 microsteps per full step
- Compact size 10x10mm QFP-44 package
- Low power dissipation, very low RDSON & synchronous rectification
- EMI-optimizes programmable slope
- Protection & Diagnostics overcurrent, short to GND, overtemperature & undervoltage
- stallGuard2 high precision sensorless motor load detection
- coolStep load dependent current control for energy savings up to 75%
- microPlyer microstep interpolation for increased smoothness with coarse step input
- spreadCycle high-precision chopper for best current sine wave form and zero crossing

요약하자면 4A, 30V 범위내의 바이폴라 모터를 돌릴 수 있고, 256 마이크로스텝을 지원하며, 여러가지 부가기능들이 있다...정도

만들어 놓은 회로도도 보자.































데이터시트의 샘플 회로를 매우 참조하였음.































내가 설계한 회로도의 R31, R32는 Rsense 저항값인데 값이 0.1 ohm 이면 전류값을 3A로 제한한다. 데이터시트의 샘플 회로도 상에서 Rsense 저항은 R3, R4 이다. 0.075 ohm 으로 설정되어 있는데 이건 전류값을 4A로 제한한다는 의미이다.
데이터시트에 이렇게 명시되어 있다.


모터 스펙에 맞춰쓰면 될거다.
그리고 SPI로도 전류를 세팅해 줄 수 있다. Rsense로 최대값을 제한해 두고 SPI로 세밀하게 전류를 설정해서 쓰는 모양이다.

TMC2660의 인터페이스는 아래와 같다.

- ENN
- SG_TST
- DIR
- STEP
- SDO
- SDI
- SCK
- CSN

SPI만으로 모터를 굴릴수 있는건 아닌거같고, 초기값 설정을 SPI로 해주고 Pulse/Dir으로 모터를 제어해 주는거 같다.
Pulse/Dir은 MCX314AL에서 제어해주면 될거고, MCU로 초기값을 SPI로 날려만 주면 되겠군.

TMC2660을 포함한 Trinamic의 모터 드라이버들은 20-bit가 SPI 통신의 기본 사이즈인거 같다.
STM32의 SPI는 8-bit or 16-bit가 기본인데 말이야.

TMC2660의 데이터시트 내용 중 SPI 관련 파트를 읽어보면 이런 내용이 있다.

If more than 20 clocks are driven, the additional bits shifted into SDI are shifted out on SDO after a 20-clock delay through an internal shift register. This can be used for daisy chaining multiple chips.

24 비트를 날려주면 최상위 4바이트는 SDO로 밀려나고 나머지 20 비트만 인식된다는 이야기 같은데...
0001 0002 0003 0004 0005 0006 이렇게 24 비트를 보내면 0001은 인식 안되고 0002 0003 0004 0005 0006 만 인식된다고 일단 생각하자.

그럼 초기화를 어떻게 시켜야 하느냐가 문제인디...
Device Initialization에 대한 내용이 데이터시트에 나온다.

 6.11 Device Initialization

The following sequence of SPI commands is an example of enabling the driver and initializing the chopper:

    SPI = $901B4;    // Hysteresis mode
    or
    SPI = $94557;    // Constant toff mode
    SPI = $D001F;    // Current setting : $d001d (max. current)
    SPI = $E0010;    // low driver strenth, stallGuard2 read, SDOFF = 0
    SPI = $00000;    // 256 microstep setting

First test of coolStep current control:
    SPI = $A8202;    // Enable coolStep with minimum current 1/4 CS

1010 1000 0010 0000 0010

The configuration parameters should be tuned to the motor and application for optimum performance.


TMC2660에는 5개의 write-only register가 존재한다.

- Driver Control Register(DRVCTRL)
- Chopper Configuration Register(CHOPCONF)
- coolStep Configuration Register(SMARTEN)
- stallGuard2 Configuration Register(SGCSCONF)
- Driver Configuration Register(DRVCONF)























DRVCTRL 레지스터는 DRVCONF 레지스터의 SDOFF 비트값에 따라 두가지 포맷을 가진다.
SDOFF 비트를 set 으로 설정하면 SPI로 모터를 컨트롤하고, clear로 설정하면 Step/Dir으로 모터를 컨트롤하게 된다.

으응??? SPI로 어떻게 모터를 돌린다는거지???

CA[7:0], CB[7:0] 레지스터의 값으로 코일 A와 B의 전류값을 세팅한다는데 아마도 이 값을 계속 변경시켜서 모터를 돌린다는 이야기 같긴 하다.


머...그건 그렇고 초기화 코드의 의미를 하나하나 확인해 보자.

그런데 아 안되겠어...타이핑을 다 할 수가 없어...

일단 저 초기화 코드에서 전류 세팅만 내가 사용할 모터에 맞게 바꾸고 나머진 그대로 쓸련다.


















1.4A에 최대한 가깝게 세팅해 주자.

SPI = $D001F; //이부분을
SPI = $D000F; //이렇게 바꾼다

하드웨어 상 3A로 전류 설정을 해놨으니까 15/32로 current scale을 설정하면 될거같다.
계산해 보면

    15/32*3 = 1.40625A

이렇다 이거지.



  //////////////////////////////////////////////////////////////////////////////
//TMC2660 Init
FT800_TxBuffer[0] = 0x09;
FT800_TxBuffer[1] = 0x45;
FT800_TxBuffer[2] = 0x57;
HAL_GPIO_WritePin(GPIOF, GPIO_PIN_13, GPIO_PIN_RESET);
HAL_SPI_TransmitReceive(&hspi1, FT800_TxBuffer, FT800_RxBuffer, 3, 100);
HAL_GPIO_WritePin(GPIOF, GPIO_PIN_13, GPIO_PIN_SET);

FT800_TxBuffer[0] = 0x0D;
FT800_TxBuffer[1] = 0x00;
FT800_TxBuffer[2] = 0x04;
HAL_GPIO_WritePin(GPIOF, GPIO_PIN_13, GPIO_PIN_RESET);
HAL_SPI_TransmitReceive(&hspi1, FT800_TxBuffer, FT800_RxBuffer, 3, 100);
HAL_GPIO_WritePin(GPIOF, GPIO_PIN_13, GPIO_PIN_SET);

FT800_TxBuffer[0] = 0x0E;
FT800_TxBuffer[1] = 0x00;
FT800_TxBuffer[2] = 0x10;
HAL_GPIO_WritePin(GPIOF, GPIO_PIN_13, GPIO_PIN_RESET);
HAL_SPI_TransmitReceive(&hspi1, FT800_TxBuffer, FT800_RxBuffer, 3, 100);
HAL_GPIO_WritePin(GPIOF, GPIO_PIN_13, GPIO_PIN_SET);

FT800_TxBuffer[0] = 0x00;
FT800_TxBuffer[1] = 0x00;
FT800_TxBuffer[2] = 0x00;
HAL_GPIO_WritePin(GPIOF, GPIO_PIN_13, GPIO_PIN_RESET);
HAL_SPI_TransmitReceive(&hspi1, FT800_TxBuffer, FT800_RxBuffer, 3, 100);
HAL_GPIO_WritePin(GPIOF, GPIO_PIN_13, GPIO_PIN_SET);
//TMC2660 Init
//////////////////////////////////////////////////////////////////////////////


TMC2660 초기화 코드를 이렇게 짜주고...아차 전류세팅은 15/32에서 4/32로 바꿨다.



          outpw(adr+wr0, 0x8000);

osDelay(200);

command(0x3,0xf);
outpw(adr+wr1, 0x0000);
outpw(adr+wr2, 0x0040);
outpw(adr+wr3, 0x0000);
expmode(0x3,0x5d08,0x497f);

accofst(0x3,0);
range(0x3,800000);
acac(0x3,1010);
dcac(0x3,1010);
acc(0x3,100);
dec(0x3,100);
startv(0x3,50);
speed(0x3,40);
pulse(0x3,10);
lp(0x3,0);
ep(0x3,0);

command(0xc,0xf);
outpw(adr+wr1, 0x0000);
outpw(adr+wr2, 0x0040);
outpw(adr+wr3, 0x0000);
expmode(0x4,0x5d08,0x01c4);
expmode(0x8,0x5d08,0x010c);

accofst(0xc,0);
range(0xc,800000);
acac(0xc,1010);
dcac(0xc,1010);
acc(0xc,100);
dec(0xc,100);
startv(0xc,50);
speed(0xc,40);
pulse(0xc,10);
lp(0xc,0);

outpw(adr+wr4, 0x0000);
outpw(adr+wr5, 0x0124);

acc(0x1,200);
speed(0x1,8000);
pulse(0x1,40000);
while(1){
command(0x1,0x20);
wait(0x1);
command(0x1,0x21);
wait(0x1);
}


MCX314AL 구동 루틴은 이렇게 만들어서 돌리보자.





ㅋㅋㅋㅋ 돈다 돌아 ㅋㅋㅋㅋ

2014/11/29

STM32에 MCX314AL을 붙여보자 -- 4. SLA7078MPR 굴려먹기

자 오늘은 드디어 모터를 돌려보자구.

MCX314AL은 4개의 axis를 구동 가능하다.

그 중 3개의 축에는 Bipolar 스텝모터 드라이버(TMC2660)를, 나머지 한개의 축에는 Unipolar 스텝모터 드라이버(SLA7078MPR)를 연결해놨다.

일단 유니폴라 스텝모터 먼저 돌려보고 바이폴라도 돌려보자.


 SLA7078MPR 스펙부터 확인해보자.

- Power supply voltages, Vbb : 46V(max), 10 to 44V normal operating range
- Logic supply voltages, Vdd : 3.0 to 5.5V
- Maximum output currents : 1A, 1.5A, 2A, 3A
- Built-in sequencer
- Simplified clock-in stepping control
- Microstepping at full-, half-, quater-, eighth-, and sixteenth-steps
- Built-in sense resistor, Rsint
- All variants are pin-compatible for enhanced design flexibility
- ZIP type 23-pin molded package(SLA package)
- Self-excitation PWM current control with fixed off-time; off-time adjusted automatically by step reference current ratio(3 levels)
- Built-in synchronous rectifying circuit reduces losses at PWM off
- Synchronous PWM chopping function prevents motor noise in Hold mode
- Sleep mode for reducing the IC input current in stand-by state
- Built-in protection circuitry against motor coil open/shorts option available

우왕 굳. 겁나 좋쿤.



























SLA7078MPR은 보호회로가 내장되어있고 3A까지 출력이 가능한 모델이다.

M1 : L, M2 : H, M3 : H 로 연결하면 16th Microstep 이 적용된다.

그리고 Clock과 F/R만 MCX314AL로 제어하면 된다 이거지.




          outpw(adr+wr0, 0x8000);

osDelay(200);

command(0x3,0xf);
outpw(adr+wr1, 0x0000);
outpw(adr+wr2, 0xe000);
outpw(adr+wr3, 0x0000);
expmode(0x3,0x5d08,0x497f);

accofst(0x3,0);
range(0x3,800000);
acac(0x3,1010);
dcac(0x3,1010);
acc(0x3,100);
dec(0x3,100);
startv(0x3,100);
speed(0x3,4000);
pulse(0x3,100000);
lp(0x3,0);
ep(0x3,0);

command(0xc,0xf);
outpw(adr+wr1, 0x0000);
outpw(adr+wr2, 0x0040); //D6 PLSMD, 1-pulse 1-direction setting.
outpw(adr+wr3, 0x0000);
expmode(0x4,0x5d08,0x01c4);
expmode(0x8,0x5d08,0x010c);

accofst(0xc,0);
range(0xc,800000);
acac(0xc,1010);
dcac(0xc,1010);
acc(0xc,100);
dec(0xc,100);
startv(0xc,50);
speed(0xc,40);
pulse(0xc,10);
lp(0xc,0);

outpw(adr+wr4, 0x0000);
outpw(adr+wr5, 0x0124);

acc(0x8,200);
speed(0x8,4000);
pulse(0x8,40000);
while(1){
command(0x8,0x20);
wait(0x8);
command(0x8,0x21);
wait(0x8);
}




기본 초기화 루틴은 2-pulse 타입으로 세팅이 되어 있는데, 1-pulse 1-direction 타입으로 변경해서 테스트 코드를 만들어 봤다.




ㅋㅋㅋ 미친듯이 도는구만 ㅋㅋㅋ












2014/11/27

STM32에 MCX314AL을 붙여보자 -- 3. 되는건지 마는건지

HardFault의 원인을 알아냈다.

FSMC 설정 중 WriteOperation이 Diable 이면 그냥 읽기만 되는 모양이다.

그래서 Enable 으로 변경하니까 문제없다.


STM32CubeMX에서 이부분을 변경하면 된다.









































타이밍은 변경없이 그대로

  /* Timing */
Timing.AddressSetupTime = 15;
Timing.AddressHoldTime = 15;
Timing.DataSetupTime = 255;
Timing.BusTurnAroundDuration = 15;
Timing.CLKDivision = 16;
Timing.DataLatency = 17;
Timing.AccessMode = FMC_ACCESS_MODE_A;
/* ExtTiming */




          outpw(adr+wr0, 0x8000);

osDelay(200);

command(0x3,0xf);
outpw(adr+wr1, 0x0000);
outpw(adr+wr2, 0xe000);
outpw(adr+wr3, 0x0000);
expmode(0x3,0x5d08,0x497f);

accofst(0x3,0);
range(0x3,800000);
acac(0x3,1010);
dcac(0x3,1010);
acc(0x3,100);
dec(0x3,100);
startv(0x3,100);
speed(0x3,4000);
pulse(0x3,100000);
lp(0x3,0);
ep(0x3,0);

command(0xc,0xf);
outpw(adr+wr1, 0x0000);
outpw(adr+wr2, 0x0000);
outpw(adr+wr3, 0x0000);
expmode(0x4,0x5d08,0x01c4);
expmode(0x8,0x5d08,0x010c);

accofst(0xc,0);
range(0xc,800000);
acac(0xc,1010);
dcac(0xc,1010);
acc(0xc,100);
dec(0xc,100);
startv(0xc,50);
speed(0xc,40);
pulse(0xc,10);
lp(0xc,0);

outpw(adr+wr4, 0x0000);
outpw(adr+wr5, 0x0124);

acc(0x3,200);
speed(0x3,4000);
pulse(0x1,80000);
pulse(0x2,40000);
command(0x3,0x22);


MCX314AML.C 파일의 main 함수내의 초기화 코드를 사용해봤다.


mcx314al의 레지스터는 구조가 매우 독특한데...문제가 좀 있어...

어떤 레지스터 번지에 데이터를 write한 후, read 해서 제대로 값이 들어갔는지 확인할 수가 없다.

그냥 Driving command를 날려서 펄스가 나오는지 확인하는거 외에는 디버깅 방법이 없다.

적어도 Chip ID 정도는 읽어서 확인할 수 있도록은 해줘야지





























일단 돌려보니까 펄스는 나온다.

우훗

2014/11/21

STM32에 MCX314AL을 붙여보자 -- 2. 드라이버를 만들자

노바 일렉트로닉스 홈페이지에 가면 MCX314AML.C 파일을 다운받을 수 있다.

MCX302/304/312/314/501을 사용하기 위한 샘플 프로그램 모음 파일인데 이중 MCX314AML.C 파일을 변경해서 모션 컨트롤 드라이버로 사용하자.

MCX314AL.C와 MCX314AL.H 파일을 만들어 봤다.

#define  adr 0x60000000 // Basic address

#define wr0 0x0 //Command register
#define wr1 0x2 //Mode register 1
#define wr2 0x4 //Mode register 2
#define wr3 0x6 //Mode register 3
#define wr4 0x8 //Output register
#define wr5 0xa //Interpolation mode register
#define wr6 0xc //Low word bits data writing register
#define wr7 0xe //High word bits data writing register

#define rr0 0x0 //Main status register
#define rr1 0x2 //Status register 1
#define rr2 0x4 //Status register 2
#define rr3 0x6 //Status register 3
#define rr4 0x8 //Input register 1
#define rr5 0xa //Input register 2
#define rr6 0xc //Low word bits data reading register
#define rr7 0xe //High word bits data reading register

#define bp1p 0x4 //BP + direction data register for the first axis control
#define bp1m 0x6 //BP ? direction data register for the first axis control
#define bp2p 0x8 //BP + direction data register for the second axis control
#define bp2m 0xa //BP ? direction data register for the second axis control
#define bp3p 0xc //BP + direction data register for the third axis control
#define bp3m 0xe //BP ? direction data register for the third axis control

void wreg1(int axis,int wdata);
void wreg2(int axis,int wdata);
void wreg3(int axis,int wdata);
void command(int axis,int cmd);
void range(int axis,long wdata);
void acac(int axis,int wdata);
void dcac(int axis,int wdata);
void acc(int axis,int wdata);
void dec(int axis,int wdata);
void startv(int axis,int wdata);
void speed(int axis,int wdata);
void pulse(int axis,long wdata);
void decp(int axis,long wdata);
void center(int axis,long wdata);
void lp(int axis,long wdata);
void ep(int axis,long wdata);
void compp(int axis,long wdata);
void compm(int axis,long wdata);
void accofst(int axis,long wdata);
void hsspeed(int axis,int wdata);
void expmode(int axis,int em6data,int em7data);
void syncmode(int axis,int sm6data,int sm7data);
long readlp(int axis);
long readep(int axis);
void wait(int axis);
void next_wait(void);
void bp_wait(void);
void homesrch(void);



#include "stm32f4xx_hal.h"
#include
#include "MCX314AL.h"

#define outpw(a, b) *(__IO uint16_t*) (a) = b
#define inpw(a) *(__IO uint16_t*) (a)

// wreg 1 (axis assignment, data) ----Write register 1 setting
void wreg1(int axis,int wdata)
{
outpw(adr+wr0, (axis << 8) + 0xf); //axis assignment
outpw(adr+wr1, wdata);
}

// wreg 2 (axis assignment, data) ----Write register 2 setting
void wreg2(int axis,int wdata)
{
outpw(adr+wr0, (axis << 8) + 0xf); //axis assignment
outpw(adr+wr2, wdata);
}

// wreg 3 (axis assignment, data) -----Write register 3 setting
void wreg3(int axis,int wdata)
{
outpw(adr+wr0, (axis << 8) + 0xf); //axis assignment
outpw(adr+wr3, wdata);
}

// command (axis assignment, data) -----For writing commands
void command(int axis,int cmd)
{
outpw(adr+wr0, (axis << 8) + cmd);
}

// range(axis assignment, data) -----For range (R) setting
void range(int axis,long wdata)
{
outpw(adr+wr7, (wdata >> 16) & 0xffff);
outpw(adr+wr6, wdata & 0xffff);
outpw(adr+wr0, (axis << 8) + 0x00);
}

// acac(axis assignment, data) -----For S-curve Deceleration increasing rate (L) setting
void acac(int axis,int wdata)
{
outpw(adr+wr6, wdata);
outpw(adr+wr0, (axis << 8) + 0x01);
}


// dcac(axis assignment, data) ----- For jerk (L) setting
void dcac(int axis,int wdata)
{
outpw(adr+wr6, wdata);
outpw(adr+wr0, (axis << 8) + 0x0e);
}

// acc(axis assignment, data) -----For acceleration/deceleration (A) setting

void acc(int axis,int wdata)
{
outpw(adr+wr6, wdata);
outpw(adr+wr0, (axis << 8) + 0x02);
}

// dec( axis assignment, data) -----For deceleration (D) setting
void dec(int axis,int wdata)
{
outpw(adr+wr6, wdata);
outpw(adr+wr0, (axis << 8) + 0x03);
}

// startv(axis assignment, data) -----For initial speed (SV) setting
void startv(int axis,int wdata)
{
outpw(adr+wr6, wdata);
outpw(adr+wr0, (axis << 8) + 0x04);
}

// speed(axis assignment, data) -----For drive speed (V) setting
void speed(int axis,int wdata)
{
outpw(adr+wr6, wdata);
outpw(adr+wr0, (axis << 8) + 0x05);
}

// pulse( axis assignment, data) -----For output pulse output/finish point (P) setting
void pulse(int axis,long wdata)
{
outpw(adr+wr7, (wdata >> 16) & 0xffff);
outpw(adr+wr6, wdata & 0xffff);
outpw(adr+wr0, (axis << 8) + 0x06);
}

// decp(axis assignment, data) -----For manual deceleration (DP) setting
void decp(int axis,long wdata)
{
outpw(adr+wr7, (wdata >> 16) & 0xffff);
outpw(adr+wr6, wdata & 0xffff);
outpw(adr+wr0, (axis << 8) + 0x07);
}

// center(axis assignment, data) -----For circular center point (C) setting
void center(int axis,long wdata)
{
outpw(adr+wr7, (wdata >> 16) & 0xffff);
outpw(adr+wr6, wdata & 0xffff);
outpw(adr+wr0, (axis << 8) + 0x08);
}

// lp(axis assignment, data) -----For logical position counter (LP ) setting
void lp(int axis,long wdata)
{
outpw(adr+wr7, (wdata >> 16) & 0xffff);
outpw(adr+wr6, wdata & 0xffff);
outpw(adr+wr0, (axis << 8) + 0x09);
}

// ep(axis assignment, data) -----For real position counter (EP) setting
void ep(int axis,long wdata)
{
outpw(adr+wr7, (wdata >> 16) & 0xffff);
outpw(adr+wr6, wdata & 0xffff);
outpw(adr+wr0, (axis << 8) + 0x0a);
}


// compp(axis assignment, data) -----For COMP+ (CP) setting
void compp(int axis,long wdata)
{
outpw(adr+wr7, (wdata >> 16) & 0xffff);
outpw(adr+wr6, wdata & 0xffff);
outpw(adr+wr0, (axis << 8) + 0x0b);
}

// compm(axis assignment, data) -----For COMP ? (CM) setting
void compm(int axis,long wdata)
{
outpw(adr+wr7, (wdata >> 16) & 0xffff);
outpw(adr+wr6, wdata & 0xffff);
outpw(adr+wr0, (axis << 8) + 0x0c);
}

// accofst(axis assignment, data) ----For acceleration counter shift (AO) setting
void accofst(int axis,long wdata)
{
outpw(adr+wr7, (wdata >> 16) & 0xffff);
outpw(adr+wr6, wdata & 0xffff);
outpw(adr+wr0, (axis << 8) + 0x0d);
}

// hsspeed(axis assignment, data) ------------------- Home Search Speed (HV) setting
void hsspeed(int axis,int wdata)
{
outpw(adr+wr6, wdata);
outpw(adr+wr0, (axis << 8) + 0x61);
}

// expmode(axis assignment, data) ------------------- Expansion Mode (EM) setting
void expmode(int axis,int em6data,int em7data)
{
outpw(adr+wr6, em6data);
outpw(adr+wr7, em7data);
outpw(adr+wr0, (axis << 8) + 0x60);
}

// syncmode(axis assignment, data) ------------------ Synchronous Mode (SM) setting
void syncmode(int axis,int sm6data,int sm7data)
{
outpw(adr+wr6, sm6data);
outpw(adr+wr7, sm7data);
outpw(adr+wr0, (axis << 8) + 0x64);
}

// readlp(axis assignment) -----For logical position counter (LP) reading
long readlp(int axis)
{
long a;long d6;long d7;
outpw(adr+wr0, (axis << 8) + 0x10);
d6 = inpw(adr+rr6);d7 = inpw(adr+rr7);
a = d6 + (d7 << 16);
return(a);
}

// readep(axis assignment) -----For real position counter (EP) reading
long readep(int axis)
{
long a;long d6;long d7;
outpw(adr+wr0, (axis << 8) + 0x11);
d6 = inpw(adr+rr6);d7 = inpw(adr+rr7);
a = d6 + (d7 << 16);
return(a);
}

// wait(axis assignment) -----For waiting for drive stop
void wait(int axis)
{
while(inpw(adr+rr0) & axis);
}

// next_wait() -----Next data setting of waiting for continuous interpolation
void next_wait(void)
{
while((inpw(adr+rr0) & 0x0200) == 0x0);
}


// bp_wait() ----- Next data setting of waiting for BP interpolation
void bp_wait(void)
{
while((inpw(adr+rr0) & 0x6000) == 0x6000);
}

// home search() ------------------------------- All axes home search
//
// ------ X axis home search ---------------------------------
// Step1 Near home (IN0) signal high-speed search in the ? direction at 20,000pps
// Step2 Home (IN1) signal low-speed search in the ? direction at 500pps
// Step3 Z-phase (IN2) signal low-speed search in the ? direction at 500pps
// Deviation counter clear output at Z-phase search
// Step4 3500 pulse offset high-speed drive in the + direction at 20,000pps
//
// ------ Y axis home search ---------------------------------
// Step1 Near home (IN0) signal high-speed search in the ? direction at 20,000pps
// Step2 Home (IN1) signal low-speed search in the ? direction at 500pps
// Step3 Z-phase (IN2) signal low-speed search in the ? direction at 500pps
// Deviation counter clear output at Z-phase search
// Step4 700 pulse offset high-speed drive in the + direction at 20,000pps
//
// ------ Z axis home search ---------------------------------
// Step1 High-speed search: None
// Step2 Home (IN1) signal low-speed search in the + direction at 400pps
// Step3 Z-phase search: None
// Step4 20 pulse offset drive in the ? direction at 400pps
//
// ------ U axis home search ---------------------------------
// Step1 High-speed search: None
// Step2 Home (IN1) signal low-speed search in the ? direction at 300pps
// Step3 Z-phase search: None
// Step4 Offset drive: None
//

void homesrch(void)
{
// X and Y axes home search parameter setting
// (See the initial setting of main for mode setting)
speed(0x3,2000); // Step1 and 4 High speed: 20000pps
hsspeed(0x3,50); // Step2 and 3 Low speed: 500pps
pulse(0x1,3500); // X axis offset: 3500 pulse
pulse(0x2,700); // Y axis offset: 700 pulse

// Z axis home search parameter setting
speed(0x4,40); // Step4 drive speed: 400pps
hsspeed(0x4,40); // Step2 search speed: 400pps
pulse(0x4,20); // Offset:20 pulses

// U axis home search parameter setting
hsspeed(0x8,30); // Step2 search speed: 300pps

command(0xf,0x62); // Execution of automatic home search for all the axes
wait(0xf); // Waits for termination of all the axes

if(inpw(adr+rr0) & 0x0010) // Error display
{
printf("X-axis Home Search Error \n");
}
if(inpw(adr+rr0) & 0x0020)
{
printf("Y-axis Home Search Error \n");
}
if(inpw(adr+rr0) & 0x0040)
{
printf("Z-axis Home Search Error \n");
}
if(inpw(adr+rr0) & 0x0080)
{
printf("U-axis Home Search Error \n");
}
}


adr을 메모리 맵에 맞게 수정해주고, outpw와 inpw만 재정의 해주면 끝인거 같다.

근데 HardFault 뜬다. 끄으

2014/11/18

STM32에 MCX314AL을 붙여보자 -- 1. FSMC로 연결하자

NOVA electronics의 모션 컨트롤러인 MCX314AL을 사용해보자.

Ali에서 검색해보니까 겁나 비싼 IC네...123달러다.

내가 이걸 왜... 걍 FPGA에 로직 올려서 팔아도 이거보다 싸겠는데...




어쨋건간에 ADDR[3:0], DATA[15:0], CSN, WRN, RDN 핀을 STM32의 FSMC에 연결했다.

H16L8 핀은 High로 연결하면 16비트, Low로 연결하면 8비트란 뜻이다. 난 16비트로 간다.

그 외 INTN, EXPLSN, RESETN은 적당히 연결해뒀다.



STM32CubeMX에서 설정한건데 STM32에서 FSMC를 써보는건 처음이라 이게 맞는지 모르겠네...


셋업/홀드 타임 설정하는 부분같은데 일단 기본값으로 가보자. 나중에 오실로 보면서 수정하든가 하고...

STM32CubeMX에서 Generate Code 하면 프로젝트를 생성해준다.

편하고 조으네..



생성된 프로젝트의 main 함수 내부에 FSMC 초기화 함수가 포함되어 있다.



아랫부분의 타이밍 설정 부분만 요리조리 손보면 금방 돌려볼 수 있을거 같은데...


이게 FSMC에 연결되는 외부 디바이스의 메모리 맵이다. MCX314AL은 NOR/PSRAM/SRAM 타입으로 연결되니까 Bank1 부분이지.


BANK1은 또 4개의 부분으로 나뉜다. STM32CubeMX의 FSMC설정 부분의 Chip Select 항목을 보면 NE1~NE4까지 설정할 수 있게 되어있다.

NE1 : 0x6000 0000 ~ 0x63ff ffff
NE2 : 0x6400 0000 ~ 0x67ff ffff
NE3 : 0x6800 0000 ~ 0x6bff ffff
NE4 : 0x6c00 0000 ~ 0x6fff fffff

이렇게 메모리 맵이 구성된다 이거지.

난 MCX314AL의 CE를 NE1에 연결했으니까 0x6000 0000를 베이스 어드레스로 사용하면 된다.

물론 첨 해보는거니까 내 생각일 뿐이다.

프로젝트도 생성했고 메모리 구조도 확인했으니 프로그램 짜서 함 돌리보자.