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/24

FT800, EVE(Embedded Video Engine) -- 4. Touch 테스트

오늘은 FT800의 터치 기능을 써먹어보자.

FT800 Programmers Guide의 5.47 CMD_CALIBRATE 항목을 유심히 읽어보자

5.47 CMD_CALIBRATE - execute the touch screen calibration routine

The calibration procedure collects three touches from the touch screen, then computes and loads an appropriate matrix into REG_TOUCH_TRANSFORM_A-F. To use it, create a display list and then use CMD_CALIBRATE. The co-processor engine overlays the touch targets on the current display list, gathers the calibration input and updates REG_TOUCH_TRANSFORM_A-F.



세 점을 터치해서 캘리브레이션 데이터를 REG_TOUCH_TRANSFORM에 저장한다. 

cmd_dlstart();
cmd(CLEAR(1,1,1));
cmt_text(80, 30, 27, OPT_CENTER, "Please tap on the dot");
cmd_calibrate();
이렇게 실행해라.

대충 이런 뜻인듯.

터치 보정 후 REG_TOUCH_TRANSFORM_A-F 레지스터의 값을 EEPROM에 저장해 두고 부팅시 저장값을 읽어와서 초기화 해주면 될거 같다.

터치 관련 레지스터나 함 찾아보자.

REG_TOUCH_ADC_MODE
-> The host can set this bit to control the ADC sampling mode of the FT800
     0 : Single Ended mode. It causes low power consumption but with less accuracy
     1 : Differential Mode. It causes higher power consumption but with more accuracy.
          The default mode after reset.

REG_TOUCH_SCREEN_XY
-> Bit[15:0] : Y coordinates of the touch screen. After doing calibration, it shall be within the height of the screen 
    size. If the touch screen is not being touched, it shall be 0x8000.
-> Bit[31:16] : X coordinates of the touch screen. After doing calibration, it shall be within the height of the screen 
    size. If the touch screen is not being touched, it shall be 0x8000.
Note : This register is the final computation output of the touch engine of the FT800. It has been mapped into screen size.

REG_TOUCH_RAW_XY
-> Bit[15:0] : raw Y coordinates of the touch screen before going through transformation matrix. 
    The valid range is from 0 to 1023. If there is no touch on screen, the value shall be 0xFFFF.
-> Bit[31:16] : raw X coordinates of the touch screen before going through transformation matrix. 
    The valid range is from 0 to 1023. If there is no touch on screen, the value shall be 0xFFFF.
Note : The coordinates in this register have not mapped into the screen coordinates. To get the screen coordinates, please refer to REG_TOUCH_SCREEN_XY.

REG_TOUCH_DIRECT_XY
-> Bit[9:0] : The 10 bit ADC value for Y coordinate.
-> Bit[25:16] : The 10 bit ADC value for X coordinate.
-> Bit[31] : 
    0 : Touch is being sensed and the two fields above contains the sensed data.
    1 : No touch is being sensed and the data in the two fields above shall be ignored.

REG_TOUCH_DIRECT_Z1Z2
-> Bit[9:0] : The 10 bit ADC value for touch screen resistance Z2.
-> Bit[25:16] : The 10 bit ADC value for touch screen resistance Z1.
Note : To know it is touched or not, please check the 31st bit of REG_TOUCH_DIRECT_XT. FT800 touch engine will do the post-processing for these Z1 and Z2 values and update the result in REG_TOUCH_RZ.

REG_ANALOG

REG_TOUCH_RZ
-> Bitp[15:0] : Resistance of touching on the touch screen. The valid value is 0 to 0x7fff.
    Highest value(0x7fff) means no touch, Lowest value(0) means maximum pressure.
    
REG_TOUCH_TRANSFORM_A-F

REG_TOUCH_TAG
-> Bit[7:0] : These bits are set as the tag value of the specific graphics object on the screen which is being touched. These bits are updated once when all the lines of the current frame is scanned out to the screen.
Note : The valid tag value range is from 1 to 255, therefore the default value of this register is zero, meaning there is no touch by default.

REG_TOUCH_TAG_XY
-> Bit[15:0] : Y coordinates of the touch screen, which was used by the touch engine to look up the tag result.
-> Bit[31:16] : X coordinates of the touch screen, which was used by the touch engine to look up the tag result.
Note : Host can read this register to check the coordinates used by the touch engine to update the tag register REG_TOUCH_TAG.

REG_TOUCH_RZTHRESH
-> Bit[15:0] : These bits control the touch screen resistance threshold. Host can adjust the touch screen touching sensitivity by setting this register. The default value after reset is 0xFFFF and it means the lightest touch will be accepted by the touch engine of the FT800. The host can set this register by doing experiments. The typical value is 1200.

REG_TOUCH_OVERSAMPLE
-> Bit[3:0] : These bits control the touch screen oversample factor. The higher value of this register causes more accuracy with more power consumption, but may not be necessary. The valid range is from 1 to 15.

REG_TOUCH_SETTLE
-> Bit[3:0] : These bits control the touch screen settle time, in the unit of 6 clocks. The default value is 3, meaning the settle time is 18(3*6) system clock cycles.

REG_TOUCH_CHARGE
-> Bit[15:0] : These bits control the touch-screen charge time, in the unit of 6 system clocks. The default value after reset is 6000, i.e. the charge time will be 6000*6 clock cycles.

REG_TOUCH_MODE
-> Bit[1:0] : The host can set these two bits to control the touch screen sampling mode of the FT800 touch engine.
    00 : off mode. No sampling happens.
    01 : Single mode. Cause one single sample to occur.
    10 : Frame mode. Cause a sample at the start of each frame.
    11 : Continuous mode. Up to 1000 time per seconds. Default mode after reset.

초기화 관련 레지스터들은 초기값으로 가도 될거같다. 

터치 처리 과정은 아마도 이렇지 않을까 싶은데...

1, 터치값을 읽어와서 REG_TOUCH_RAW_XY에 저장한다.
2. 보정값을 이용해서 스크린 좌표값으로 변경한 후 REG_TOUCH_SCREEN_XY에 저장한다.
3. 2번 값으로 tag를 찾는다.

설명이 너무 느슨해서 정확한 의미를 알기가 어려운데...실제로 써보면서 확인해보자.

일단은 캘리브레이션부터

  FT800_DLstart();
FT800_DL(CLEAR_COLOR_RGB(64,64,64));
FT800_DL(CLEAR(1,1,1));
FT800_DL(COLOR_RGB(0xff,0xff,0xff));
FT800_Text((480/2), (272/2), 27, OPT_CENTER, "Please Tap on the dot");
FT800_Calibrate(0);
FT800_Flush_Co_Buffer();
FT800_WaitCmdfifo_empty();



머 이런식이다.


 
FT800_Track(249, 86, 1, 1, 1);
FT800_Flush_Co_Buffer();
FT800_WaitCmdfifo_empty();

FT800_DLstart();
FT800_DL(CLEAR_COLOR_RGB(0,0,0));
FT800_DL(CLEAR(1,1,1));
FT800_DL(TAG(1));
FT800_Dial(249, 86, 55, 0, 0x8000);
FT800_DL(DISPLAY());
FT800_Swap();
FT800_Flush_Co_Buffer();
FT800_WaitCmdfifo_empty();

while(1){
TR_Val = ft800memRead32(REG_TRACKER);
if((TR_Val & 0xff) == 1)
color = TR_Val >> 16;

do{
cmdBufferRd = ft800memRead16(REG_CMD_READ);
cmdBufferWr = ft800memRead16(REG_CMD_WRITE);
printf("%x, %x\r\n", cmdBufferRd, cmdBufferWr);
}while(cmdBufferWr != cmdBufferRd);

FT800_DLstart();
FT800_DL(CLEAR_COLOR_RGB(0,0,0));
FT800_DL(CLEAR(1,1,1));
FT800_DL(TAG(1));
FT800_Dial(249, 86, 55, 0, color);
FT800_DL(DISPLAY());
FT800_Swap();
FT800_Flush_Co_Buffer();
FT800_WaitCmdfifo_empty();


되긴 되네.

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/20

FT800, EVE(Embedded Video Engine) -- 3. 돌려봅시다

MBED용 라이브러리를 IAR용으로 바꿔봤다.

FT800.h

FT800.c

잘 돌아 갈래나 모르겠네...


FT800 Programmers Guide의 2.2.5 Initialization Sequence 에는 초기화 시퀀스를 아래와 같이 소개한다.

Initialization Sequence during the boot up:
1. Use MCU SPI clock not more than 11MHz
2. Send Host Command "CLKEXT" to FT800
3. Send Host Command "ACTIVE" to enable clock to FT800
4. Configure video timing registers, except REG_PCLK
5. Write first display list
6. Write REG_DLSWAP, FT800 swaps display list immediately
7. Enable back light control for display
8. Wriet REG_PCLK, video output begins with the first display list
9. Use MCU SPI clock not more than 30MHz






























Initialization Sequence from Power Down using PD_N pin:
1. Drive the PD_N pin high
2. Wait for at least 20ms
3. Execute "Initialization Sequence during the Boot Up" from step 1 to 9

Initialization Sequence from Sleep Mode:
1. Send Host command "ACTIVE" to enable clock to FT800
2. Wait for at least 20ms
3. Execute "Initialization Sequence during Boot Up" from steps 5 to 8

Initialization sequence from standby mode:
Execute all the steps mentioned in "Initialization Sequence from Sleep Mode" except waiting for at least 20ms in step 2.


AN240 FT800 From thr Ground Up 문서의 4.2 Configuration 항목도 함 보자.

4.2 Configuration

  4.2.1 MCU setup

    4.2.1.1 SPI
      - <= 10MHz initial SPI clock
        -> Use slower clock while on internal oscillator
      - Mode zero
        -> CPOL = 0 - clock idles at zero
        -> CPHA = 0 - data is sampled on rising edge, propagated on falling edge
      - Little Endian data byte ordering

  4.2.2 Wake Up
  After configuring the MCU interface the first step in communicating with the FT800 is to wake it up.

    1) Reset the FT800
      - Drive PD_N low for 20ms, then back high
      - Wait for 20ms after PD_N is high
    2) Issue the Wake-up command
      - Write 0x00, 0x00, 0x00
    3) If using an external crystal or clock source on the FT800, issue the external clock command
      - Write 0x44, 0x00, 0x00
    4) Set the FT800 internal clock speed to 48MHz
      - Wriet 0x62, 0x00, 0x00
    5) At this point, the Host MCU SPI Master can change the SPI clock up to 30MHz
    6) Read the Device ID register
      - Read one byte from location 0x102400
      - Check for the value 0x7C
    7) Set bit 7 of REG_GPIO to 0 to turn off the LCD_DISP signal
      - Write 0x80 to location 0x102490

  4.2.3 Configuring the Display Timing
  Once the FT800 is awake and the internal clock set and Device ID checked, the next task is to configure the LCD display parameters for the chosen display with the values determined in Section 2.3.3 above.

    1) Set REG_PCLK to zero - This disables the pizel clock output while the LCD and other system parameters are configured
    2) Set the following registers with values for the chosen display. Typical WQVGA and QVGA values are shown:


























    3) Enable or disable REG_CSPREAD with a value of 01h or 00h, respectively. Enabling REG_CSPREAD will offset the R, G, and B output bits so all they do not all change at the same time.

  4.2.4 Configure the Touch Sensitivity

생략

  4.2.5 Configure the audio

생략

  4.2.6 Initialize and enable the display
  At this point, all the necessary configuration registers are initialized and the system is ready to start displaying video, as well as sensing touch events and playing audio. All of this is done through a Display List.

The Display List

 The Display List is formed by writing a series of commands to the RAM_DL memory portion of the FT800 memory map. Graphics elements are handled through commands stored in the list. Register writes for touch and audio elements are handled in line with the Display List.

The FT800 is then instructed to "swap" the Display List that was just created to make it active. While the active list is being shown on the LCD panel, or touch and audio activities processed, a new Display List is formed. Once ready, the lists swap again so the new commands are executed. This process continues for each update shown on the display, new audio sound, etc.


Display list commands are always 32 bits long. The first command on a display list should be to address 0. Subsequent commands should be sent on an increment of 4 bytes to avoid overlap.

Since the system is just starting, there is not active Display List, and the pixel clock is not yet started. The first Display List should start with a blank screen of a chosen color as an initial condition to avoid displaying any artifacts once the pixel clock is started. Here is an example start-up Display List:

    wr32(RAM_DL + 0, CLEAR_COLOR_REG(0,0,0));
    wr32(RAM_DL + 4, CLEAR(1,1,1));
    wr32(RAM_DL + 8, DISPLAY());
    wr32(REG_DLSWAP, SWAP_FRAME);

wr32(address, value) indicates the MCU would write the value (CLEAR, POINT_SIZE, etc.) to the address within the display list (RAM_DL + n). This notation is used throughout other FT800 documents.

Up until this point, no output has been generated on the LCD interface. With the configuration and initial display list in place, the LCD DISP signal, backlight and pixel clock can now be turned on:

머 그렇탄다...

초기화 함수 함 만들어봤다

void FT800_Init(void){

  uint16_t cmdBufferWr, cmdBufferRd;


  HAL_GPIO_WritePin(GPIOC, GPIO_PIN_4, GPIO_PIN_SET);

  HAL_Delay(20);

  HAL_GPIO_WritePin(GPIOC, GPIO_PIN_4, GPIO_PIN_RESET);

  HAL_Delay(20);

  HAL_GPIO_WritePin(GPIOC, GPIO_PIN_4, GPIO_PIN_SET);

  HAL_Delay(20);

       
  ft800cmdWrite(FT800_CLKEXT);

  HAL_Delay(5);

  ft800cmdWrite(FT800_ACTIVE);

  HAL_Delay(5);

  ft800memWrite16(REG_HCYCLE, 548);

  ft800memWrite16(REG_HOFFSET, 43);

  ft800memWrite16(REG_HSYNC0, 0);

  ft800memWrite16(REG_HSYNC1, 41);

  ft800memWrite16(REG_VCYCLE, 292);

  ft800memWrite16(REG_VOFFSET, 12);

  ft800memWrite16(REG_VSYNC0, 0);

  ft800memWrite16(REG_VSYNC1, 10);

  ft800memWrite8(REG_SWIZZLE, 0);

  ft800memWrite8(REG_PCLK_POL, 1);

  ft800memWrite8(REG_CSPREAD, 1);

  ft800memWrite16(REG_HSIZE, 480);

  ft800memWrite16(REG_VSIZE, 272);


  ft800memWrite32(RAM_DL, CLEAR_COLOR_RGB(0,0,0));

  ft800memWrite32(RAM_DL+4, CLEAR(1,1,1));

  ft800memWrite32(RAM_DL+8, DISPLAY());

  ft800memWrite32(REG_DLSWAP, DLSWAP_FRAME);

  ft800memWrite8(REG_PCLK, 5);


  HAL_Delay(50);

       
  ft800memWrite32(RAM_DL, CLEAR(1,1,1));

  ft800memWrite32(RAM_DL+4, BEGIN(1));

  ft800memWrite32(RAM_DL+8, VERTEX2II(220,110,31,'F'));

  ft800memWrite32(RAM_DL+12, VERTEX2II(244,110,31,'T'));

  ft800memWrite32(RAM_DL+16, VERTEX2II(270,110,31,'D'));

  ft800memWrite32(RAM_DL+20, VERTEX2II(299,110,31,'I'));

  ft800memWrite32(RAM_DL+24, END());

  ft800memWrite32(RAM_DL+28, COLOR_RGB(160,22,22));

  ft800memWrite32(RAM_DL+32, POINT_SIZE(320));

  ft800memWrite32(RAM_DL+36, BEGIN(2));

  ft800memWrite32(RAM_DL+40, VERTEX2II(192,133,0,0));

  ft800memWrite32(RAM_DL+44, END());

  ft800memWrite32(RAM_DL+48, DISPLAY());

       
  ft800memWrite32(REG_DLSWAP, DLSWAP_FRAME);


  MX_SPI1_Init_HIGH();

}









































와 나온다

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를 베이스 어드레스로 사용하면 된다.

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

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

FT800, EVE(Embedded Video Engine) -- 2. 라이브러리 어떻게 할까.

스펙은 겁나게 맘에 드는데...

라이브러리는???

FTDI 애네 IAR ARM 라이브러리는 지원을 안해주네....어쩌라는거지


FTDI 홈페이지에서 확인 가능한 라이브러리는 Arduino, ARM, PIC 가 있다.


이 중 ARM과 PIC은 영 쓸게 아닌거 같고, Arduino는 잘 만들었지만 난 STM32를 쓰거든...



MBED에도 라이브러리가 있는 모양이다.


http://developer.mbed.org/users/dreschpe/code/FT800/

오케이 이걸 IAR용 C로 바꾸면 쓸만할거 같다.

이걸 베이스로 하자.

2014/11/17

FT800, EVE(Embedded Video Engine) -- 1. 일단 스펙 읽어보고 하드웨어를 준비하자.

USB 관련 디바이스만 만들던 FTDI가 밑도 끝도 없이 툭 내 놓은 EVE 시리즈...

MCU 기반 시스템에서 매우 큰 리소스를 점유하는 LCD를 SPI로 간단히 제어할 수 있다. 우와아!!!

보통 AVR, PIC, Cortex-M 정도의 MCU에서 Character LCD가 아닌 TFT-LCD를 구동하기는 쉽지가 않다. 단순히 정지화면만 뿌려주는거야 쉽게 구현가능하지만, 사용자의 입력을 받아서 처리한 후 화면에 뿌려주는건 어렵지...처리 속도도 그렇고 내부 용량도 그렇고...

난 MCU를 사용하는 시스템에 외부 메모리는 되도록 인터페이스하지 않는다. 별로 많지도 않은 IO를 메모리 전용으로 쓰기엔 너무 아까워서 눈물이 나니까...차라리 메모리가 좀 더 많은 디바이스를 선택하는게 낫다.

그러니까 주로 Character LCD, 좀 무리하면 흑백 그래픽 LCD 정도나 쓰지...
TFT-LCD는 리눅스 올라가는 임베디드 시스템 아니면 쳐다도 못봤지. 지금까진



MBED와 Arduino에서 돌리는 영상이다. STM32나 AVR에서 저정도로 TFT-LCD를 굴려먹을 수 있다. 우왕 신난다.



EVE(Embedded Video Engine) 시리즈는 현재 FT800과 FT801 두 가지를 사용할 수 있다.
일단 특징부터 보자.

- Targets QVGA/WQVGA displays with 1/16th resolution, maximum 512x512 resolution
- 18-bit interface with 2-bit color dither offering 262K color palette with 24-bit quality
- Store up to 2000 objects/commands in 8K byte display list
- FT800 with integrated touch controller; FT801 with I2C capacitive touch interface
- PWM output for programmable display brightness
- Anti-aliasing algorithms improve display perception
- Low-power - 24mA typical in active mode
- Integrated audio synthesizer outputs beeps, tones or recorded audio
- Support audio playback for PCM, 4bit ADPCM and u-Law coding formats
- Extended temperature range : -40 ~ 85

최대 512x512 해상도를 지원하고 320x240, 480x272 해상도를 타겟으로 한다. 2비트 디더링으로 24비트 RGB를 처리해줌. 터치, 사운드 지원하고 저전력형이고... 등등등




MCU와 FT800간의 인터페이스는 SPI로, I2C도 지원되지만 최대 3.4MHz 니까 30MHz까지 지원되는 SPI를 써야지.

Backlight 디밍 컨트롤용 PWM 핀이 있으니까 LED Driver 회로와 Audio AMP 회로만 넣으면 회로 설계는 끝이다.

정말 이걸로 LCD를 돌릴 수 있나??? 정말 이게 단가??? 터치하고 오디오는 정말 된다는건가???
싶을정도다.


FT800 데이터시트에 레퍼런스 회로도를 제공한다.


개발용 보드로 판매하는 VM800C 를 구매해서 사용하는것도 좋다. 개당 65달라 정도인거 같다.

근데 난 회로를 만들었지...
LCD를 미리 선정해놔서 어쩔수가 없다. LCD 핀맵이 다르다...ㅠㅠ


내가 사용할 LCD는 LTE430WQ-F0C-0BS 로 4.3인치 터치 LCD다.
이거 LCD 핀맵으로 설계했다.



백라이트는 다이렉트로 30V 넣어주고, 사운드는 일단 빼고 만들었다.



보드는 이런 느낌...

사운드도 넣고 LED 드라이버도 추가해 줄 생각이다.



자 다음엔 FT800 드라이버를 만들어보자.


ps. IC 가격을 깜빡했네. 엘레먼트14는 현재 1~99 단위로 $8.76
      디지키에 좀더 싼 가격대가 있기는 하다.