2014/02/18

Nios II 시작해보자-4(SPI-Software)

NIOS II EDS 실행해서 프로젝트 만들고

아래와 같이 만들어봤다.
#include "sys/alt_stdio.h"
#include "system.h"
#include <stdlib .h>
#include "altera_avalon_spi_regs.h"

#define _NOP() asm ("nop")

unsigned char RxBuffer1[32];
unsigned char RxCounter1 = 0;

int UART1_get_Number(void){
unsigned char key_value, i;
int KeyIn;

do{
key_value = alt_getchar();
alt_putchar(key_value);
if(key_value == '\r'){
RxBuffer1[RxCounter1]='\0';
alt_putstr("\r\n");
KeyIn = atoi(RxBuffer1);

RxCounter1 = 0;
for(i = 0; i < 32; i++)
RxBuffer1[i] = 0;

return KeyIn;
}
else
RxBuffer1[RxCounter1++] = key_value;
}while((key_value != '\r')&&(RxCounter1 != 32));

}

int main()
{
int tmp, sum, avg, i, j, k, l;
alt_u16 write_data[1], read_data[1], adcs[15];
alt_u16 adc_ch, adc_cmd;

alt_putstr("20131118_1\r\n");
alt_putstr("1. HELP : Show menu explanation\r\n");
alt_putstr("2. Read ADS7961S\r\n");
alt_putstr("anonymous>");

/* Event loop never exits. */
while (1){
tmp = UART1_get_Number();

switch(tmp){
case 1:
alt_putstr("1. HELP : Show menu explanation\r\n");
alt_putstr("2. Read ADS7961S\r\n");
break;
case 2:
alt_putstr("2. Read ADS7961S\r\n");

//0010 01xx x000 0000
write_data[0] = 0x2400;
alt_avalon_spi_command(SPI_0_BASE, 0,
1, write_data,
0, read_data,
0);

for(i=0;i<16;i++){
alt_avalon_spi_command(SPI_0_BASE, 0,
0, write_data,
1, read_data,
0);
adcs[read_data[0]>>12] = read_data[0];
}

for(i=0;i<16;i++)
alt_printf("adc_ch %x : %x\r\n",i, (adcs[i]>>4) & 0xff);

break;
default :
alt_putstr("Invalid input value\r\n");
break;
}
alt_putstr("anonymous>");
}
return 0;
}



ADS7961S는 Manual, Auto-1, Auto-2 라는 세가지 채널 시퀀싱 모드를 제공한다.
난 Auto-1 모드를 선택해서 써볼란다.

write_data[0] =  0x2400;
alt_avalon_spi_command(SPI_0_BASE, 0,
1, write_data,
0, read_data,
0);
0x2400을 write해서 Auto-1 모드를 선택한다.

for(i=0;i<16;i++){
alt_avalon_spi_command(SPI_0_BASE, 0,
0, write_data,
1, read_data,
0);
adcs[read_data[0]>>12] = read_data[0];
}
16번 read해서 16채널의 adc 값을 읽어온다.

이게 다지 머



제대로 돌아가는지 함 돌려보자.

시발 좆같은 오실로를 쓰고있어서 파형 저장도 안돼고 나 썅.




























CH1 : MISO
CH2 : SCLK
CH3 : MOSI

인데 클럭말곤 안나오네. 0x2400 시그널이 왜 안나오지??

SPI read 부분은 빼고 0x1234를 write해서 시그널을 다시 확인해보자.
    //0010 01xx x000 0000
//write_data[0] = 0x2400;
write_data[0] = 0x1234;
alt_avalon_spi_command(SPI_0_BASE, 0,
1, write_data,
0, read_data,
0);
#if 0
for(i=0;i<16;i++){
alt_avalon_spi_command(SPI_0_BASE, 0,
0, write_data,
1, read_data,
0);
adcs[read_data[0]>>12] = read_data[0];
}

for(i=0;i<16;i++)
alt_printf("adc_ch %x : %x\r\n",i, (adcs[i]>>4) & 0xff);
#endif





























응??
0x0034??
앞에 12는 어디간겨??

int alt_avalon_spi_command(alt_u32 base, alt_u32 slave,
alt_u32 write_length, const alt_u8 * write_data,
alt_u32 read_length, alt_u8 * read_data,
alt_u32 flags)
Nios의 SPI 관련 함수의 선언부다...만 먼가 좀 이상하군 난 분명히 16bit width로 설정했는데 왜 write_data, read_data가 8bit지?? 하위 8bit만 write되고, 하위 8bit만 read되는 상황인디...

내가 머리가 나빠서 왜 저렇게 만든건진 모르것고 변수 선언부를 alt_u16으로 수정했다.

int alt_avalon_spi_command(alt_u32 base, alt_u32 slave,
alt_u32 write_length, const alt_u16 * write_data,//changed 16bit
alt_u32 read_length, alt_u16 * read_data, //changed 16bit
alt_u32 flags)
{
const alt_u16 * write_end = write_data + write_length; //changed 16bit
alt_u16 * read_end = read_data + read_length; //changed 16bit

alt_u32 write_zeros = read_length;
alt_u32 read_ignore = write_length;
alt_u32 status;

/* We must not send more than two bytes to the target before it has
* returned any as otherwise it will overflow. */
/* Unfortunately the hardware does not seem to work with credits > 1,
* leave it at 1 for now. */
alt_32 credits = 1;

/* Warning: this function is not currently safe if called in a multi-threaded
* environment, something above must perform locking to make it safe if more
* than one thread intends to use it.
*/

IOWR_ALTERA_AVALON_SPI_SLAVE_SEL(base, 1 << slave);

/* Set the SSO bit (force chipselect) only if the toggle flag is not set */
if ((flags & ALT_AVALON_SPI_COMMAND_TOGGLE_SS_N) == 0) {
IOWR_ALTERA_AVALON_SPI_CONTROL(base, ALTERA_AVALON_SPI_CONTROL_SSO_MSK);
}

/*
* Discard any stale data present in the RXDATA register, in case
* previous communication was interrupted and stale data was left
* behind.
*/
IORD_ALTERA_AVALON_SPI_RXDATA(base);

/* Keep clocking until all the data has been processed. */
for ( ; ; )
{

do
{
status = IORD_ALTERA_AVALON_SPI_STATUS(base);
}
while (((status & ALTERA_AVALON_SPI_STATUS_TRDY_MSK) == 0 || credits == 0) &&
(status & ALTERA_AVALON_SPI_STATUS_RRDY_MSK) == 0);

if ((status & ALTERA_AVALON_SPI_STATUS_TRDY_MSK) != 0 && credits > 0)
{
credits--;

if (write_data < write_end)
IOWR_ALTERA_AVALON_SPI_TXDATA(base, *write_data++);
else if (write_zeros > 0)
{
write_zeros--;
IOWR_ALTERA_AVALON_SPI_TXDATA(base, 0);
}
else
credits = -1024;
};

if ((status & ALTERA_AVALON_SPI_STATUS_RRDY_MSK) != 0)
{
alt_u32 rxdata = IORD_ALTERA_AVALON_SPI_RXDATA(base);

if (read_ignore > 0)
read_ignore--;
else
*read_data++ = (alt_u16)rxdata; //changed 16bit
credits++;

if (read_ignore == 0 && read_data == read_end)
break;
}

}

/* Wait until the interface has finished transmitting */
do
{
status = IORD_ALTERA_AVALON_SPI_STATUS(base);
}
while ((status & ALTERA_AVALON_SPI_STATUS_TMT_MSK) == 0);

/* Clear SSO (release chipselect) unless the caller is going to
* keep using this chip
*/
if ((flags & ALT_AVALON_SPI_COMMAND_MERGE) == 0)
IOWR_ALTERA_AVALON_SPI_CONTROL(base, 0);

return read_length;
}



자 다시 돌려보자.





























좀 흔들렸네...어쨌든 0x1234 나왔다.

SPI write는 확인했고, 다음은 read를 확인해보자.
0x1234를 0x2400으로 바꾸고 주석처리한 부분도 해제해서 돌려보자.





























오케이 ADC값이 나온다.
10번 채널에 33이 출력된다. 16비트 데이터 중 상위 4비트는 채널값이고 그 다음 8비트가 ADC 값이다. 하위 4비트는 Don't care.















시리얼로 출력은 이렇게 나온다. 0x21 = 33























ADS7961S의 10번 채널에 센싱 저항을 연결해서 LED 듀티를 변경하면서 adc 값을 읽어봤다.

잘 되네.








댓글 없음:

댓글 쓰기