|
|
View previous topic :: View next topic |
Author |
Message |
zilog Guest
|
MAX3110 driver not working |
Posted: Tue Jun 19, 2007 12:46 pm |
|
|
I have tried adopting the code originally submitted by Ttelmah to work with my setup, but I seem to need to receive one character to fully empty the TX buffer - anyone spot anything fishy in the code below?
I use SSP2 on a PIC18F, using EXT_INT1 for /IRQ, and PIN_D3 for /CS.
Code: |
//These are for a 18F chip
#byte INTCON3 = 0xFF0
#bit EXT1IF = INTCON3.0
#define CS PIN_D3
//Buffer tests and handling
#define MaxBufIsEmpty(buff,in,out,size) (in==out)
#define MaxBufHasData(buff,in,out,size) (in!=out)
#define MaxBufIsFull(buff,in,out,size) (((++in)&(size-1))==out)
#define MaxBufToBuff(buff,in,out,size,chr) { \
buff[in]=chr;\
in=((++in) & (size-1));\
if (in==out) \
out=((++out) & (size-1));\
}
#define MaxBufFromBuff(buff,in,out,size) (MaxbTemp=out,\
out=(++out) & (size-1), \
buff[MaxbTemp])
#define MaxBufClrBuff(buff,in,out,size) {in=0;\
out=0;}
//Declares for buffers. I have three others not shown here
#define MAXSIBUFF (32)
#define MAXSOBUFF (64)
void isr_maxim(void);
int16 SSPtransfer16(int16 val);
void Maxputc(int8 chr);
void MaxInit(int8 baud_index);
int8 MaxKbHit(void);
int8 MaxGetc(void);
int8 MAXIPbuff[MAXSIBUFF],MAXIPin,MAXIPout;
int8 MAXOPbuff[MAXSOBUFF],MAXOPin,MAXOPout;
int8 MaxbTemp;
unsigned int16 MaxConfigWord;
//Defines for the SSP port again for a 18F chip
#byte SSP2BUF = 0xF66
#byte SSP2STAT = 0xF64
#bit BF = SSP2STAT.0
/* Now the SSP handler code. Using my own, since the supplied routines test the wrong way round for my needs */
#DEFINE READ_SSP2() (SSP2BUF)
#DEFINE WAIT_FOR_SSP2() while(!BF)
#DEFINE WRITE_SSP2(x) SSP2BUF = (x)
#INT_EXT1 NOCLEAR //Interrupt from Maxim chip
void isr_maxim(void) {
unsigned int16 Rxdata;
do {
EXT1IF = 0;
//force a read
Rxdata = SSPtransfer16(0L);
if (Rxdata & 0x8000L) {
//Here a receive character is present
MaxBufToBuff(MAXIPbuff, MAXIPin, MAXIPout, MAXSIBUFF, make8(Rxdata, 0));
}
if (Rxdata & 0x4000L) {
//Here the chips TX buffer is empty
if (MaxBufHasData(MAXOPbuff,MAXOPin,MAXOPout,MAXSOBUFF)) {
Rxdata = SSPtransfer16(0x8000L | make16(0, MaxBufFromBuff(MAXOPbuff, MAXOPin, MAXOPout, MAXSOBUFF)));
//Check if a byte was received with the transmission
if (Rxdata & 0x8000L) {
MaxBufToBuff(MAXIPbuff, MAXIPin, MAXIPout, MAXSIBUFF, make8(Rxdata, 0));
}
//empty=false;
} else {
//empty=true;
MaxConfigWord &= (~0x0800L);
//disable transmitter interrupt
SSPtransfer16(MaxConfigWord);
}
}
} while (EXT1IF);
return;
}
int16 SSPtransfer16(int16 val) {
int8 msb;
//routine to send and receive a 16bit value from the Maxim chip
//Latch the data at this point
output_low(CS);
//send high byte
WRITE_SSP2(make8(val,1));
WAIT_FOR_SSP2();
msb=READ_SSP2();
//now send the low byte
WRITE_SSP2(make8(val,0));
WAIT_FOR_SSP2();
output_high(CS);
return (make16(msb, READ_SSP2()));
}
//Subroutines to talk to the Maxim chip.
void Maxputc(int8 chr) {
int16 tval;
DISABLE_INTERRUPTS(INT_EXT1);
MaxBufToBuff(MAXOPbuff, MAXOPin, MAXOPout, MAXSOBUFF, chr);
//empty=false;
MaxConfigWord |= 0xC800;
tval = SSPtransfer16(MaxConfigWord);
//Force an interrupt event - bodge!...
EXT1IF = 1;
ENABLE_INTERRUPTS(INT_EXT1);
return;
}
int8 MaxKbHit(void)
{
return (MaxBufHasData(MAXIPbuff, MAXIPin, MAXIPout, MAXSIBUFF));
}
int8 MaxGetc(void)
{
return (MaxBufFromBuff(MAXIPbuff, MAXIPin, MAXIPout, MAXSIBUFF));
}
void MaxInit(int8 baud_index) {
//init SPI2
setup_spi2(SPI_MASTER | SPI_L_TO_H | SPI_CLK_DIV_4 | SPI_XMIT_L_TO_H);
output_high(CS);
//enable external INT1
clear_interrupt(INT_EXT1);
ext_int_edge(1, H_TO_L);
enable_interrupts(INT_EXT1);
// clear buffers
MaxBufClrBuff(MAXIPbuff, MAXIPin, MAXIPout, MAXSIBUFF);
MaxBufClrBuff(MAXOPbuff, MAXOPin, MAXOPout, MAXSOBUFF);
baud_index &= 0xF;
//RX INT enabled, TX INT disabled, RX FIFO on, 8N1 format
MaxConfigWord = 0xC400L + make16(0,baud_index);
//Ensure chip has accepted the data
do {
SSPtransfer16(MaxConfigWord);
if (((SSPtransfer16(0x4000L) ^ MaxConfigWord) & 0x3FFF)==0)
break;
} while(true);
return;
}
|
|
|
|
Guest
|
|
Posted: Tue Jun 19, 2007 1:04 pm |
|
|
To clarify - it transmits 6-8 characters and then waits for a RX-character to transmit the rest of the buffer. |
|
|
Guest
|
|
Posted: Tue Jun 19, 2007 1:10 pm |
|
|
Now I saw that the slower the SPI-bus clocks, the more characters I get before it needs RX to continue.. SPI_CLK_DIV_64 lets me transmit 32 characters before it stalls. |
|
|
zilog Guest
|
|
Posted: Tue Jun 19, 2007 2:43 pm |
|
|
I have tried lowering the clock frequency from 40MHz to 10MHz, this also makes the code work. |
|
|
Ttelmah Guest
|
|
Posted: Tue Jun 19, 2007 3:07 pm |
|
|
You appear to be reading the interrupt flag, not the interrupt _input_. The latter is vital. The PIC, is an 'edge triggered' interrupt chip. The MAX3110, gives a _level_ output. Hence you need to be reading the actual input, not the state of the interrupt flag.
The original form is:
Code: |
#INT_EXT NOCLEAR //Interrupt from Maxim chip
void MAXIM(void) {
unsigned int16 Rxdata;
do {
//force a read
Rxdata = iSSPtransfer16(0L);
if (Rxdata & 0x8000L) {
//Here a receive character is present
tobuff(MAXIPbuff,MAXIPin,MAXIPout,SIBUFF,make8(Rxdata,0));
}
if (Rxdata & 0x4000L) {
//Here the chips TX buffer is empty
if (hasdata(MAXOPbuff,MAXOPin,MAXOPout,SOBUFF)) {
Rxdata=iSSPtransfer16(0x8000L | make16(0,ifrombuff(MAXOPbuff,MAXOPin,MAXOPout,SOBUFF)));
//Check if a byte was received with the transmission
if (Rxdata & 0x8000L) {
tobuff(MAXIPbuff,MAXIPin,MAXIPout,SIBUFF,make8(Rxdata,0));
}
empty=false;
}
else {
empty=true;
Mconfig &= (~0x0800L);
//disable transmitter interrupt
iSSPtransfer16(Mconfig);
}
}
} while (INTINPUT==0);
clear_interrupts(INT_EXT);
}
|
Best Wishes |
|
|
zilog Guest
|
|
Posted: Tue Jun 19, 2007 3:22 pm |
|
|
Ttelmah,
I have tried the latter version of the code aswell, to no help. The code still behaves the same. I have routed the INT1-pin to the D7-pin as well since I use RB4-7 for change-trigging and cant disturb this by reading port B. See the code that also doesnt work below:
Code: |
#INT_EXT1 NOCLEAR //Interrupt from Maxim chip
void isr_maxim(void) {
unsigned int16 Rxdata;
do {
//force a read
Rxdata = iSSPtransfer16(0L);
if (Rxdata & 0x8000L) {
//Here a receive character is present
MaxBufToBuff(MAXIPbuff, MAXIPin, MAXIPout, MAXSIBUFF, make8(Rxdata, 0));
}
if (Rxdata & 0x4000L) {
//Here the chips TX buffer is empty
if (MaxBufHasData(MAXOPbuff, MAXOPin, MAXOPout, MAXSOBUFF)) {
Rxdata = iSSPtransfer16(0x8000L | make16(0, MaxBufiFromBuff(MAXOPbuff, MAXOPin, MAXOPout, MAXSOBUFF)));
//Check if a byte was received with the transmission
if (Rxdata & 0x8000L) {
MaxBufToBuff(MAXIPbuff, MAXIPin, MAXIPout, MAXSIBUFF, make8(Rxdata, 0));
}
//empty=false;
} else {
//empty=true;
MaxConfigWord &= (~0x0800L);
//disable transmitter interrupt
iSSPtransfer16(MaxConfigWord);
}
}
} while (input(pin_d7) == 0);
clear_interrupt(INT_EXT1);
return;
}
|
|
|
|
Ttelmah Guest
|
|
Posted: Wed Jun 20, 2007 3:05 am |
|
|
A couple of other comments:
On the original code, there is a separate 'SSPtransfer16', and 'iSSPtransfer16'. The latter is only used in the interrupts, and prevents interrupts from being disabled in the main code, when this transfer routine is used. It is necessary to have the two copies, and manually control the interrupts, or the compiler will still add the extra interrupt control code, which gave problems....
Second comment, though the compiler should handle it correctly, you do not want/need a return on void handlers.You want to drop off the end of these.
I would clear the external interrupt _after_ setting the interrupt edge. If you change the interrupt edge, this can generate an interrupt. Probably not your problem, but the sequence should always be:
set edge
clear interrupt
enable interrupt.
What happens if you use the original global interrupt enable/disable in MaxPutc, instead of the individual one?. Though with the code as shown, either should work, I had a problem with timing on the Max chip, if a serial receive interrupt occurred during the data transfer to the chip. Hence the global enable/disable...
I notice you are bypassing the 'empty' flagging in the original code. This was done to handle exactly the behaviour you are seeing. The Maxim chip, seems to have a fault, of not updating it's internal registers immediately, which can lead to the interrupt handler returning, yet there still being data to send. The empty flag, was used with a bodge to restart the transmission if this happens, by calling the interrupt handler, one 'extra' time.
Best Wishes |
|
|
zilog Guest
|
|
Posted: Wed Jun 20, 2007 5:39 am |
|
|
Ttelmah,
The code you posted on the forum is not complete, you set "empty" along with other flags, but you never read or declare it etc. Could you please mail me the complete code for this chip? gnuffel (at) gmail dot com. |
|
|
Ttelmah Guest
|
|
Posted: Wed Jun 20, 2007 6:59 am |
|
|
It was complete. The very first code I posted was not, I was having problems like yours. If you search back in the very old forum posts, on the 3110, you will find my original question, where I was having the problem that the the device would not complete 'sending' data, unless a character was rceived. This sounds exactly like what you are describing.
The latter code posted on the forum, was fully working, however the variable declaration could well have been missed.
Empty is just an int1, set when the transmit interrupt is turned off in the interrupt handler.
The 'bodge' was in the main, to 'poll' this, and if it was found 'on', with data present in the buffer, to clear it, and force an interrupt.
Why it should be needed, I could never see. If data is added to the buffer, the interrupt will always be called, so 'extra' calls should not be needed. It is as if the chip's interrupt output was not being updated to reflect the TX interrupt being enabled, till after one character is transferred...
Best Wishes |
|
|
zilog Guest
|
|
Posted: Wed Jun 20, 2007 7:47 am |
|
|
I have now found that the /IRQ pin of the MAX never returns high, not even with a 3k9 pullup. Ddebugging the SPI tells me that the MAX cries "empty" allt he time, but the command to disable interrutps simply doesnt matter. All SPI communication tells me its sane, but he IRQ-pin is stone dead tied to GND.
Could this be a broken chip where the open drain output has been fused? |
|
|
zilog Guest
|
|
Posted: Wed Jun 20, 2007 8:02 am |
|
|
I have now made some more tests on the 3110, when powered down, the IRQ-output is floating while after power-on it is pulled strong low, even if I dont initialize the chip at all (SPI lines disconnected and grounded). |
|
|
zilog Guest
|
|
Posted: Thu Jul 05, 2007 1:04 pm |
|
|
I have got the code workign now (broken INT-line on the PIC was the reason). A new problem has arisen - if I call Maxputc repeatedly, either by itseld or through printf(Maxputc, "......"); it scrambles the order of the characters, casues some characters to repeat etc.
My main routine calls "void MaxKeepMAX3110Alive(void)" repeatedly to make sure the chip doesnt stall. I have attached the complete code below - please help me find the problem as I need this chip for debug.
Code: |
#include "styrkort.h"
//These are for a 18F chip
#byte INTCON3 = 0xFF0
#bit EXT2IF = INTCON3.1
#define CS PIN_D3
//Buffer tests and handling
#define MaxBufIsEmpty(buff,in,out,size) (in==out)
#define MaxBufHasData(buff,in,out,size) (in!=out)
#define MaxBufIsFull(buff,in,out,size) (((++in)&(size-1))==out)
#define MaxBufToBuff(buff,in,out,size,chr) { \
buff[in]=chr;\
in=((++in) & (size-1));\
if (in==out) \
out=((++out) & (size-1));\
}
#define MaxBufFromBuff(buff,in,out,size) (MaxbTemp=out,\
out=(++out) & (size-1), \
buff[MaxbTemp])
#define MaxBufiFromBuff(buff,in,out,size) (MaxibTemp=out,\
out=(++out) & (size-1), \
buff[MaxibTemp])
#define MaxBufClrBuff(buff,in,out,size) {in=0;\
out=0;}
//Declares for buffers. I have three others not shown here
#define MAXSIBUFF (32)
#define MAXSOBUFF (64)
void isr_maxim(void);
int16 SSPtransfer16(int16 val);
int16 iSSPtransfer16(int16 val);
void Maxputc(int8 chr);
void MaxInit(int8 baud_index);
int8 MaxKbHit(void);
int8 MaxGetc(void);
void MaxKeepMAX3110Alive(void); //call this in idle loop to make sure buffers are managed
int8 MAXIPbuff[MAXSIBUFF],MAXIPin,MAXIPout;
int8 MAXOPbuff[MAXSOBUFF],MAXOPin,MAXOPout;
int8 MaxbTemp, MaxibTemp;
int1 MaxEmpty;
unsigned int16 MaxConfigWord;
//Defines for the SSP port again for a 18F chip
#byte SSP2BUF = 0xF66
#byte SSP2STAT = 0xF64
#bit BF = SSP2STAT.0
/* Now the SSP handler code. Using my own, since the supplied routines test the wrong way round for my needs */
#DEFINE READ_SSP2() (SSP2BUF)
#DEFINE WAIT_FOR_SSP2() while(!BF)
#DEFINE WRITE_SSP2(x) SSP2BUF = (x)
#INT_EXT2 NOCLEAR //Interrupt from Maxim chip
void isr_maxim(void) {
unsigned int16 Rxdata;
do {
clear_interrupt(INT_EXT2);
//force a read
Rxdata = iSSPtransfer16(0L);
if (Rxdata & 0x8000L) {
//Here a receive character is present
MaxBufToBuff(MAXIPbuff, MAXIPin, MAXIPout, MAXSIBUFF, make8(Rxdata, 0));
}
if (Rxdata & 0x4000L) {
//Here the chips TX buffer is empty
if (MaxBufHasData(MAXOPbuff, MAXOPin, MAXOPout, MAXSOBUFF)) {
Rxdata = iSSPtransfer16(0x8000L | make16(0, MaxBufiFromBuff(MAXOPbuff, MAXOPin, MAXOPout, MAXSOBUFF)));
//Check if a byte was received with the transmission
if (Rxdata & 0x8000L) {
MaxBufToBuff(MAXIPbuff, MAXIPin, MAXIPout, MAXSIBUFF, make8(Rxdata, 0));
}
MaxEmpty=false;
} else {
MaxEmpty=true;
MaxConfigWord &= (~0x0800L);
//disable transmitter interrupt
iSSPtransfer16(MaxConfigWord);
}
}
} while (input(pin_d7) == 0);
return;
}
int16 SSPtransfer16(int16 val) {
int8 msb;
//routine to send and receive a 16bit value from the Maxim chip
//Latch the data at this point
output_low(CS);
//send high byte
WRITE_SSP2(make8(val,1));
WAIT_FOR_SSP2();
msb=READ_SSP2();
//now send the low byte
WRITE_SSP2(make8(val,0));
WAIT_FOR_SSP2();
output_high(CS);
return (make16(msb, READ_SSP2()));
}
int16 iSSPtransfer16(int16 val) {
int8 msb;
//routine to send and receive a 16bit value from the Maxim chip
//Latch the data at this point
output_low(CS);
//send high byte
WRITE_SSP2(make8(val,1));
WAIT_FOR_SSP2();
msb=READ_SSP2();
//now send the low byte
WRITE_SSP2(make8(val,0));
WAIT_FOR_SSP2();
output_high(CS);
return (make16(msb, READ_SSP2()));
}
//Subroutines to talk to the Maxim chip.
void Maxputc(int8 chr) {
int16 tval;
DISABLE_INTERRUPTS(INT_EXT2);
MaxBufToBuff(MAXOPbuff, MAXOPin, MAXOPout, MAXSOBUFF, chr);
MaxEmpty=false;
MaxConfigWord |= 0xC800;
tval = SSPtransfer16(MaxConfigWord);
//Force an interrupt event - bodge!...
EXT2IF = 1;
ENABLE_INTERRUPTS(INT_EXT2);
return;
}
int8 MaxKbHit(void)
{
return (MaxBufHasData(MAXIPbuff, MAXIPin, MAXIPout, MAXSIBUFF));
}
int8 MaxGetc(void)
{
return (MaxBufFromBuff(MAXIPbuff, MAXIPin, MAXIPout, MAXSIBUFF));
}
void MaxKeepMAX3110Alive(void)
{
if (!MaxEmpty)
EXT2IF = 1;
return;
}
void MaxInit(int8 baud_index) {
//init SPI2
setup_spi2(SPI_MASTER | SPI_L_TO_H | SPI_CLK_DIV_4 | SPI_XMIT_L_TO_H);
output_high(CS);
// clear buffers
MaxBufClrBuff(MAXIPbuff, MAXIPin, MAXIPout, MAXSIBUFF);
MaxBufClrBuff(MAXOPbuff, MAXOPin, MAXOPout, MAXSOBUFF);
MaxEmpty = true;
baud_index &= 0xF;
//RX INT enabled, TX INT disabled, RX FIFO on, 8N1 format
MaxConfigWord = 0xC400L + make16(0,baud_index);
//Ensure chip has accepted the data
do {
SSPtransfer16(MaxConfigWord);
if (((SSPtransfer16(0x4000L) ^ MaxConfigWord) & 0x3FFF)==0)
break;
} while(true);
//enable external INT2
ext_int_edge(2, H_TO_L);
clear_interrupt(INT_EXT2);
enable_interrupts(INT_EXT2);
return;
}
|
|
|
|
Ttelmah Guest
|
|
Posted: Fri Jul 06, 2007 2:29 am |
|
|
The only thing in the original code, that would cause the data order to be scrambled, is if you are over filling the buffers. The code does not check for this (assuming that your buffers _are_ large enough), and this would result in data becoming scrambled...
Best Wishes |
|
|
Guest
|
|
Posted: Fri Jul 06, 2007 7:57 am |
|
|
Ttelmah wrote: | The only thing in the original code, that would cause the data order to be scrambled, is if you are over filling the buffers. The code does not check for this (assuming that your buffers _are_ large enough), and this would result in data becoming scrambled...
Best Wishes |
I have discovered that lowering the SPI clock lessens the problem somewhat, but not completely.
I cant see how filling the buffers would cause tokens to be pairwise swapped, repeated etc. |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|