Tool/software: TI-RTOS
My current setup is - PC(TwinCAT) --> EtherCAT --> ET1100 piggyback --> SPI --> TI DSP
Everything works perfectly when I transmit/receive less than one FIFO buffer full of data bytes. When I want to call the transmit/receive functions in a loop to transmit/receive more than one FIFO buffer of data, it does not work as intended. Please help me identify the problem because I read the code atleast 20 times but cannot see an error.
There is NO interrupt usage.
/*
* SOES Simple Open EtherCAT Slave
*
* File : esc_hw.c
* Version : 0.9.2
* Date : 22-02-2010
* Copyright (C) 2007-2010 Arthur Ketels
*
* SOES is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License version 2 as published by the Free
* Software Foundation.
*
* SOES is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* As a special exception, if other files instantiate templates or use macros
* or inline functions from this file, or you compile this file and link it
* with other works to produce a work based on this file, this file does not
* by itself cause the resulting work to be covered by the GNU General Public
* License. However the source code for this file must still be made available
* in accordance with section (3) of the GNU General Public License.
*
* This exception does not invalidate any other reasons why a work based on
* this file might be covered by the GNU General Public License.
*
* The EtherCAT Technology, the trade name and logo "EtherCAT" are the intellectual
* property of, and protected by Beckhoff Automation GmbH.
*/
/* Device header file */
#include <stdint.h> /* Includes uint16_t definition */
#include <stdbool.h> /* Includes true/false definition */
#include <DSP281x_Device.h>
#include "utypes.h"
#include "esc.h"
#include "esc_coe.h"
#include "CPU.h" // Local include file
#define ESC_ETHERCAT_READ 0x02
#define ESC_ETHERCAT_READ_WAIT 0x03
#define ESC_ETHERCAT_WRITE 0x04
#define ESC_ETHERCAT_3BYTEADDR 0x06
#define ESC_ETHERCAT_WAIT 0xFF
#define ESC_ETHERCAT_CONTINUE 0x00
#define ESC_ETHERCAT_RDTERMINATE 0xFF
#define CPU_RATE 16.667L // for a 60MHz CPU clock speed
#define DELAY_US(A) DSP28x_usDelay(((((long double) A * 1000.0L) / (long double)CPU_RATE) - 9.0L) / 5.0L)
/*---------------------------------------------------------------------------------------------------------------------
; F U N C T I O N D E F I N I T I O N S
;----------------------------------------------------------------------------------------------------------------------
*/
void InitGpio(void)
{
EALLOW;
// IER = 0x0000;
// IFR = 0x0000;
// Enable the four I/O pins for the SPI interface
GpioMuxRegs.GPFMUX.bit.SPISIMOA_GPIOF0 = 1; // Slave In, Master Out
GpioMuxRegs.GPFMUX.bit.SPISOMIA_GPIOF1 = 1; // Slave Out, Master In
GpioMuxRegs.GPFMUX.bit.SPICLKA_GPIOF2 = 1; // Serial Clock
GpioMuxRegs.GPFMUX.bit.SPISTEA_GPIOF3 = 1; // Slave Transmit Enable (SYNC)
EDIS;
}
void InitSPI(void)
{
EALLOW;
// Initialize SPI FIFO registers
SpiaRegs.SPICCR.bit.SPISWRESET=0; // Reset SPI
SpiaRegs.SPICCR.bit.SPICHAR = 0x7; // Character Length = 8
SpiaRegs.SPICCR.bit.CLKPOLARITY = 1; // Rising edge
SpiaRegs.SPICTL.bit.SPIINTENA = 1; // Enabled
SpiaRegs.SPICTL.bit.TALK = 1; //
SpiaRegs.SPICTL.bit.MASTER_SLAVE = 1; // Master mode
SpiaRegs.SPICTL.bit.CLK_PHASE = 0; // 1/2-cycle delay of Clk wrt SPISTEA (0 - no delay, 1 - delay)
SpiaRegs.SPICTL.bit.OVERRUNINTENA = 1; // Overrun Interrupt enabled
//ClkCfgRegs.LOSPCP.all = 0x1; // 0 = sysclk/1 = 200M; 1 = sysclk/2 = 100M
SpiaRegs.SPISTS.all=0x0000; // Clear Status bits (TxBufFull,INT, Overrun)
SpiaRegs.SPIBRR=0x0005; // Baud Rate = LSPCLK / (SPIBRR+1) [LSPCLK=SysClk/4 by default=50M]
//---------------------------------------------------------------------------------------------
SpiaRegs.SPIFFTX.all=0xC022; // Enable FIFO's, reset them, set TX FIFO IntLevl = 2,TXINT disabled
SpiaRegs.SPIFFTX.bit.TXFFIENA = 0; // Disable TXFF INT
SpiaRegs.SPIFFRX.all=0x006A; // Enable FIFO's, reset them, set RXFFIL= 10(dec)
SpiaRegs.SPIFFRX.bit.RXFFIL = 0x02;
SpiaRegs.SPIFFRX.bit.RXFFIENA = 0; // disable RXFF INT
//----------------------------------------------------------------------------------------------
SpiaRegs.SPIFFCT.all=0x00; // FFTXDLY = 0 (delay btw Tx transfers)
SpiaRegs.SPIPRI.all=0x0020; // Stop after transaction complete on EmuStop
SpiaRegs.SPICCR.bit.SPISWRESET=1; // Enable SPI
SpiaRegs.SPIFFTX.bit.TXFIFO=1; // Reset Tx FIFO
SpiaRegs.SPIFFRX.bit.RXFIFORESET=1;
EDIS;
}
/******************************************************************************
* Function: void ESC_read(uint16_t address, uint16_t *buf,
* uint16_t len, uint16_t *tALevent))
*
* PreCondition: SPI initialized
* EthetCAT initialized
*
* Input: uint16_t address = EtherCAT register address
* uint16_t *buf = Pointer to write data to
* uint16_t len = Size of data to read
*
* Output: uint16_t *tALevent = Status returned
*
* Side Effects: None
*
* Overview: This is the main EthetCAT read function
*****************************************************************************/
void ESC_read(uint16_t offset_addr, void *buf, uint16_t len, void *tALevent)
{
uint16_t i,cmd, numwords = 0, j;
static uint16_t readval =0;
uint16_t *ptr = (uint16_t *)0;
uint16_t readphase[16]; // FIFO=16,Up to 13 words can be read (Addrphase takes 2Addr+1WS)
uint16_t loop_count = 0;
ptr = (uint16_t *)tALevent;
if(len > 0 && len <= 26) //It is only possible to read 26 bytes of payload (+4 bytes of address) at a time from the TI SPI's FIFO
{
// Construct Address cmd bytes into 16-bit words for SPI xmission,
// SPI xmits MSBit 1st, so must swap bytes in this 16b word for transmission
// Byte order of READ cmd sequence:
// Byte 0: A[12:5]
// Byte 1: A[4:0], 110b (110b is 3-byte cmd extension)
// Byte 2: A[15:13], CMD[2:0], 00b (011b is READ w/ WS)
// Byte 3: FFh (Wait State)
//cmd = offset_addr & 0x1f
cmd =(offset_addr & 0x1FE0)<<3; // offset_addr[12:5] is 1st address phase byte, shift to upper byte
cmd |= (((offset_addr & 0x1F) << 3) | ESC_ETHERCAT_3BYTEADDR);
readphase[0] = cmd;
numwords++;
readphase[1] = (offset_addr & 0xE000) | (ESC_ETHERCAT_READ_WAIT <<10) | ESC_ETHERCAT_WAIT;
numwords++;
for(i=2, j = 0; j<len ; i++, j+=2) //numwords is in no. of bytes;
{
readphase[i] = (uint16_t) ESC_ETHERCAT_CONTINUE;
numwords++;
}
readphase[--i] |= (ESC_ETHERCAT_RDTERMINATE); // set last byte as 0xFF
/*Disable Interrupts*/
DINT;
for(i = 0; i < numwords; i++)
{
while(SpiaRegs.SPISTS.bit.BUFFULL_FLAG == 1);
SpiaRegs.SPITXBUF = readphase[i] & (0xFF00);
while(SpiaRegs.SPISTS.bit.BUFFULL_FLAG == 1);
SpiaRegs.SPITXBUF = ((readphase[i] & (0xFF)) << 8);
loop_count++;
}
if(loop_count != numwords)
{
asm(" ESTOP0");
while(1);
}
CPU_DELAY_US(5);
j = numwords;
while(SpiaRegs.SPIFFRX.bit.RXFFST < j);
readval = (SpiaRegs.SPIRXBUF) & 0xFF; // Read to tALevent
*(ptr) = (readval & 0xFF);
CPU_DELAY_US(5); //delay before reading next byte
readval = (SpiaRegs.SPIRXBUF) & 0xFF; // Read to tALevent
*(ptr) |= ((readval & 0xFF) << 8);
CPU_DELAY_US(5); //delay before reading next byte
readval = SpiaRegs.SPIRXBUF; // ignore
CPU_DELAY_US(5); //delay before reading next byte
readval = SpiaRegs.SPIRXBUF; // ignore
CPU_DELAY_US(5); //delay before reading next byte
ptr = (uint16_t *)buf;
for(i=0;((SpiaRegs.SPIFFRX.bit.RXFFST != 0));i++)
{
readval = (SpiaRegs.SPIRXBUF) & 0xFF;
ptr[i]= (readval & 0xFF);
CPU_DELAY_US(2); //delay before reading next byte
readval = (SpiaRegs.SPIRXBUF) & 0xFF;
ptr[i] |= (readval & 0xFF)<<8;
CPU_DELAY_US(2); //delay before reading next byte
}
SpiaRegs.SPIFFRX.bit.RXFIFORESET = 0; //reset the FIFO pointer
SpiaRegs.SPIFFRX.bit.RXFIFORESET = 1; //reenable the FIFO operation
/*Enable Interrupts*/
EINT;
CPU_DELAY_US(10); //delay before reading next byte
}
}
void ESC_readBlock(uint16_t* pData, uint16_t offset_addr,uint16_t numbytes)
{
uint16_t i = 0, current_bytes = 0;
if(numbytes & 0x1)
{
current_bytes = (numbytes + 0x1); // even align
}
else
{
current_bytes = numbytes;
}
while(current_bytes > 0) // input is actually in bytes
{
if( current_bytes >= 26)
{
ESC_read(offset_addr + (2*i), (void *) &pData[i], 26, (void *) &ESCvar.ALevent);
current_bytes -= 26;
i+= 13; // data is in 16 bits
}
else
{
ESC_read(offset_addr + (2*i), (void *) &pData[i], current_bytes, (void *) &ESCvar.ALevent);
current_bytes = 0;
}
}
}
/******************************************************************************
* Function: void ESC_write(uint16_t address, uint16_t *buf,
* uint16_t len, uint16_t *tALevent)
*
* PreCondition: SPI initialized
* EthetCAT initialized
*
* Input: uint16_t address = EtherCAT register address
* uint16_t *buf = Pointer read data from
* uint16_t len = Size of data to write
*
* Output: uint16_t *tALevent = Status returned
*
* Side Effects: None
*
* Overview: This is the main EthetCAT write function
*****************************************************************************/
void ESC_write(uint16_t offset_addr, void *wrdata, uint16_t len, void *tALevent)
{
uint16_t i, j,cmd, readval, numwords = 0;
uint16_t wptr,highbyte,lowbyte;
uint16_t *ptr = (uint16_t *)0;
uint16_t writephase[16];
if(len >0 && len <= 26) //It is only possible to transmit 26 bytes of payload (+4 bytes of address) at a time from the TI SPI's FIFO
{
// Construct Address cmd bytes into 16-bit words for SPI xmission,
// SPI xmits MSBit 1st, so must swap bytes in this 16b word for transmission
// Byte order of READ cmd sequence:
// Byte 0: A[12:5]
// Byte 1: A[4:0], 110b (110b is 3-byte cmd extension)
// Byte 2: A[15:13], CMD[2:0], 00b (110b is 3-byte cmd extension)
// Byte 3: A[15:13], CMD[2:0], 00b (100b is READ w/ WS)
//cmd = offset_addr & 0x1f
cmd =(offset_addr & 0x1FE0)<<3; // offset_addr[12:5] is 1st address phase byte, shift to upper byte
cmd |= (((offset_addr & 0x1F) << 3) | ESC_ETHERCAT_3BYTEADDR);
writephase[0] = cmd;
numwords++;
cmd = 0x0000;
cmd = (((offset_addr & 0xE000) >> 8) | (ESC_ETHERCAT_3BYTEADDR << 2)) << 8;
cmd |= (((offset_addr & 0xE000) | (ESC_ETHERCAT_WRITE <<10)) >> 8);
writephase[1] = cmd;
numwords++;
ptr = (uint16_t *) wrdata;
wptr=0;
for(i=2, j = 0; j < len ; i++, wptr++)
{
// Swap Bytes so low-byte goes first since ET110 i/f uses BYTE addressing
lowbyte = ptr[wptr] << 8;
j++;
highbyte = ptr[wptr] >> 8;
j++;
writephase[i] = highbyte | lowbyte;
numwords++;
}
/*Disable Interrupts*/
DINT;
for(i=0;i<numwords;i++)
{
while(SpiaRegs.SPISTS.bit.BUFFULL_FLAG == 1);
SpiaRegs.SPITXBUF = writephase[i] & (0xFF00);
while(SpiaRegs.SPISTS.bit.BUFFULL_FLAG == 1);
SpiaRegs.SPITXBUF = ((writephase[i] & (0xFF)) << 8);
}
CPU_DELAY_US(10);
j = numwords;
ptr = (uint16_t *)tALevent;
while(SpiaRegs.SPIFFRX.bit.RXFFST < j);
readval = (SpiaRegs.SPIRXBUF) & 0xFF;
*(ptr) = (readval & 0xFF);
CPU_DELAY_US(2); //delay before reading next byte
readval = (SpiaRegs.SPIRXBUF) & 0xFF;
*(ptr) |= ((readval & 0xFF) << 8);
CPU_DELAY_US(2); //delay before reading next byte
while(SpiaRegs.SPIFFTX.bit.TXFFST != 0);
SpiaRegs.SPIFFTX.bit.TXFIFO=0; // Reset Tx FIFO
SpiaRegs.SPIFFTX.bit.TXFIFO=1; // Reset Tx FIFO
SpiaRegs.SPIFFRX.bit.RXFIFORESET=0;
SpiaRegs.SPIFFRX.bit.RXFIFORESET=1;
/*Enable Interrupts*/
EINT;
CPU_DELAY_US(10); //delay before reading next byte
}
}
void ESC_writeBlock(uint16_t* pData, uint16_t offset_addr,uint16_t numbytes)
{
uint16_t i = 0; //, current_bytes = 0;
uint16_t temp_value, temp_ALevent, current_bytes;
current_bytes = numbytes;
while(current_bytes > 0) // input is actually in bytes
{
if( current_bytes >= 26)
{
ESC_write (offset_addr + (2*i), (void *) &pData[i], 26, (void *) &ESCvar.ALevent);
current_bytes -= 26;
i+= 13; // data is in 16 bits
}
else
{
if(current_bytes & 0x1) //Checking if the remaining bytes are ODD
{
// current_bytes = numbytes + 0x1; // even align
ESC_write (offset_addr+ (2*i), (void *) &pData[i], current_bytes-1, (void *) &ESCvar.ALevent);
//now send the last byte with extra alignment bytes
// note that we read the adjacent byte and write it back
ESC_read (offset_addr+(numbytes-1), (void *)&temp_value, 2, (void *) &temp_ALevent);
temp_value &= 0xFF00;
temp_value |= (pData[numbytes-1]) & 0xFF;
ESC_write (offset_addr+(numbytes-1), (void *)&temp_value, 2, (void *) &temp_ALevent);
}
else
{
ESC_write (offset_addr + (2*i), (void *) &pData[i], current_bytes, (void *) &ESCvar.ALevent);
}
current_bytes = 0;
}
}
}
