View previous topic :: View next topic |
Author |
Message |
davt
Joined: 07 Oct 2003 Posts: 66 Location: England
|
trying to contact Mark |
Posted: Fri Oct 29, 2004 4:35 am |
|
|
Hi Mark
You provided me with some code for DMX512 reception a number of months ago. I am trying to implement your code example but am having difficulty.
I was wondering if you could help me.
Kind regards.
Dave |
|
|
Mark
Joined: 07 Sep 2003 Posts: 2838 Location: Atlanta, GA
|
|
Posted: Fri Oct 29, 2004 5:03 pm |
|
|
Sure just ask away |
|
|
davt
Joined: 07 Oct 2003 Posts: 66 Location: England
|
|
Posted: Sat Oct 30, 2004 12:27 pm |
|
|
Mark
Thanks a lot!
I will post the code on Monday when I get back to work.
Thanks again.
Dave |
|
|
Mark
Joined: 07 Sep 2003 Posts: 2838 Location: Atlanta, GA
|
|
Posted: Mon Nov 01, 2004 9:41 pm |
|
|
Okay, this code is actually from dave. He was having trouble posting it.
Code: |
#include <16f767.h>
#define on 1
#define off 0
#define high 1
#define low 0
#define yes 0
#define no 1
#define wait_for_next_byte 0
#define wait_for_break 1
#define wait_for_start 2
#define wait_for_data 3
#define receive_data 4
#define start_conversion 1
#define ad_red 0x41
#define ad_blue 0x49
#define ad_green 0x51
#use delay(clock=16000000)
#byte trisa = 0x85
#byte trisb = 0x86
#byte trisc = 0x87
#byte porta = 0x05
#byte portb = 0x06
#byte portc = 0x07
#byte intcon = 0x0b
#byte adcon0 = 0x1f
#byte adcon1 = 0x9f
#byte adcon2 = 0x9b
#byte adresh = 0x1e
#byte adresl = 0x9e
#byte pir1 = 0x0c
#byte RCSTA = 0x18
#byte rcreg = 0x1a
#byte pie1 = 0x8c
#byte txsta = 0x98
#byte spbrg = 0x99
#bit brgh = txsta.2
#bit sync = txsta.4
//#bit rcie = pie1.5
#bit SPEN = RCSTA.7
#bit CREN = RCSTA.4
//#bit ferr = rcsta.2
//#bit oerr = rcsta.1
#bit rx9 = RCSTA.0
#bit rcif = pir1.5
#bit rcie = pie1.5
#bit gie = intcon.7
#bit peie = intcon.6
#bit ad_go_done = adcon0.2
#bit led = portb.7 // reception indicator
#bit test1 = portb.6 // scope test pin 1
#bit test2 = portb.5 // scope test pin 2
#bit test3 = portb.4 // scope test pin 3
void interrupt_usart_rx(void);
//////////////////////////////////// global variables //////////////////////////////
unsigned int16 dmx_512_offset; // channel number??
unsigned int16 dmx_512_count=0;
unsigned char rx_state;
unsigned char level; // the lamp level as transmitted by the dmx fader
unsigned char data; // data we are receiving
short toggle, break_found;
////////////////////////////////////////////////////////////////////////////////////
#int_rda
void interrupt_usart_rx(void)
{
union rcsta_reg
{
unsigned char bte;
struct
{
unsigned char rx9d:1;
unsigned char oerr:1;
unsigned char ferr:1;
unsigned char adden:1;
unsigned char cren:1;
unsigned char sren:1;
unsigned char rx9:1;
unsigned char spen:1;
} bits;
} rcsta;
while(rcif)
{
led=on; // reception led on;
rcsta.bte=RCSTA; // copy rx status reg
data=rcreg;
// read data - reading data also clears 'rcif' flag
// and reading 'rcreg' will cause the second 'rcsta' to be loaded if there is one
//led=off; // reception led off;
if(rcsta.bits.oerr)
{
CREN=0; // reset
CREN=1; // receive logic - clears 'oerr' bit
// we just received a buffer overun so wait for a good data byte before we look for
// a break signal
rx_state=Wait_for_next_byte;
led=off; // reception led off;
return;
}
// no overun error so continue
/////////////////////////////// state machine //////////////////////////////////
if(break_found) // find break point, rx_state = wait for break
{
rx_state=wait_for_break;
}
switch (rx_state)
{
case wait_for_next_byte:
if(!rcsta.bits.ferr)
{
rx_state=wait_for_break;
break_found=no;
dmx_512_count=0;
// reset dmx count to zero because we are looking for a break
}
break;
/*******************************************************/
case wait_for_break: // check for a framing error
if(rcsta.bits.ferr)
{
// if we did receive a framing error, make sure that the data is 0.
// this means we did receive the break signal for at least 44us
if(!data)
{
rx_state=wait_for_start;
break_found=yes;
dmx_512_count=0;
// we have found a break so reset dmx count to zero
}
}
break; // read next data byte which should be 0 (start code)
/********************************************************/
case wait_for_start: test2=on; //ok to here
// check for a framing error. if we receive one we will have to wait
// until we receive a good data byte before we begin looking for our break signal
if(rcsta.bits.ferr)
{
rx_state=wait_for_next_byte;
}
else
{ //test2=on;
if(!data)
// the start code for our data packet should always begin with 0
{
// here we determine where in the dmx stream we should begin
// receiving data based on our dmx offset address.
if(dmx_512_offset==1)
{
rx_state=receive_data;
}
else
{
rx_state=wait_for_data;
dmx_512_count=1;
}
}
else
{
rx_state=wait_for_break;
break_found=no;
}
}
break;
/*******************************************************/
case wait_for_data:
// check for a framing error. If we receive one then we need to wait until
// we receive a good data byte before we begin looking for our break signal
if(rcsta.bits.ferr)
// this could be a break signal indicating the start of the dmx stream
{
if(!data)
{
rx_state=wait_for_start;
}
else
{
rx_state=wait_for_next_byte;
}
}
else
{
// keep track of the number of bytes received so that we will know when to
// start receiving data
dmx_512_count++;
if(dmx_512_count == dmx_512_offset)
{
rx_state=receive_data;
}
}
break;
/*******************************************************/
case receive_data:
// check for framing error - if we receive a framing error then this might
// be the beggining of a new packet or a true framing error
if(rcsta.bits.ferr)
{
// if this is the beginning of the next frame then data must be 0
// else this is a framing error
if(!data)
{
rx_state=wait_for_start;
}
else
{
rx_state=wait_for_next_byte;
}
}
else
{
level=data; // store the data received in ' level '
// our 'level' has been found so wait for break
rx_state=wait_for_break;
break_found=no;
}
}
}
led=off; // reception led off;
return;
}
void main(void)
{
trisa=0b00000111;
trisb=0b00000000;
trisc=0b10000000; // set rc7 rx as an input
setup_oscillator(OSC_NORMAl);
/////////////////////////////////////////
spbrg=0x00; // set up
brgh=low; // baudrate to 250.000
sync=0; // enable asynchronous reception
spen=1; // serial port enabled - rc7/rx/dt , rc6/tx/ck pins as serial port pins
rx9=1; // 9 bit reception
/////////////////////////////////////////
break_found=no;
gie=1; // enable all interrupts
peie=1; // enable peripheral interrupts
rcie=1; // enable receive interrupt
dmx_512_offset=1; // channel number??
dmx_512_count=0;
CREN=1; // enable reception
led=off; // reception led off
test1=0; // oscilloscope
test2=0; // test
test3=0; // pins
level=0;
while(1)
{
if(level==255) // my dmx512 test generator is moved upto max level
// so I should be able to see output test 3 on oscilloscope
{
test3=on;
}
else
{
test3=off;
}
}
}
|
|
|
|
Mark
Joined: 07 Sep 2003 Posts: 2838 Location: Atlanta, GA
|
|
Posted: Mon Nov 01, 2004 9:43 pm |
|
|
dave,
I was pretty swamped today. I'll pull out the dmxter tomorrrow and have a look. |
|
|
davt
Joined: 07 Oct 2003 Posts: 66 Location: England
|
|
Posted: Tue Nov 02, 2004 3:13 am |
|
|
Thanks for that Mark!
I am still working on it!
Dave |
|
|
Mark
Joined: 07 Sep 2003 Posts: 2838 Location: Atlanta, GA
|
|
Posted: Tue Nov 02, 2004 10:16 am |
|
|
You should add #case at the top of you program.
rcsta & RCSTA are the same thing without it
Code: | rcsta.bte=RCSTA; // copy rx status reg
|
I believe this is one problem.
I modified it just a bit and had to make a couple of logic changes for the LEDs for my test hardware:
Code: | #int_rda
void interrupt_usart_rx(void)
{
union rcsta_reg
{
unsigned char bte;
struct
{
unsigned char rx9d:1;
unsigned char oerr:1;
unsigned char ferr:1;
unsigned char adden:1;
unsigned char cren:1;
unsigned char sren:1;
unsigned char rx9:1;
unsigned char spen:1;
} bits;
} rcsta;
static unsigned char rx_state=wait_for_break;
unsigned char data; // data we are receiving
while(rcif)
{
led=0; // reception led on;
rcsta.bte=RCSTA; // copy rx status reg
data=rcreg;
// read data - reading data also clears 'rcif' flag
// and reading 'rcreg' will cause the second 'rcsta' to be loaded if there is one
//led=off; // reception led off;
if(rcsta.bits.oerr)
{
CREN=0; // reset
CREN=1; // receive logic - clears 'oerr' bit
// we just received a buffer overun so wait for a good data byte before we look for
// a break signal
rx_state=wait_for_next_byte;
led=1; // reception led off;
return;
}
// no overun error so continue
// if(break_found) // find break point, rx_state = wait for break
// {
// rx_state=wait_for_break;
// }
/////////////////////////////// state machine //////////////////////////////////
switch (rx_state)
{
case wait_for_next_byte:
if(!rcsta.bits.ferr)
{
rx_state=wait_for_break;
// break_found=no;
// dmx_512_count=0;
// reset dmx count to zero because we are looking for a break
}
break;
/*******************************************************/
case wait_for_break: // check for a framing error
if(rcsta.bits.ferr)
{
// if we did receive a framing error, make sure that the data is 0.
// this means we did receive the break signal for at least 44us
if(!data)
{
rx_state=wait_for_start;
// break_found=yes;
// dmx_512_count=0;
// we have found a break so reset dmx count to zero
}
}
break; // read next data byte which should be 0 (start code)
/********************************************************/
case wait_for_start:
// check for a framing error. if we receive one we will have to wait
// until we receive a good data byte before we begin looking for our break signal
if(rcsta.bits.ferr)
{
rx_state=wait_for_next_byte;
}
else
{
// the start code for our data packet should always begin with 0
if(!data)
{
// here we determine where in the dmx stream we should begin
// receiving data based on our dmx offset address.
if(dmx_512_offset==1)
{
rx_state=receive_data;
}
else
{
rx_state=wait_for_data;
dmx_512_count=1;
}
}
else
{
rx_state=wait_for_break;
break_found=no;
}
}
break;
/*******************************************************/
case wait_for_data:
// check for a framing error. If we receive one then we need to wait until
// we receive a good data byte before we begin looking for our break signal
// this could be a break signal indicating the start of the dmx stream
if(rcsta.bits.ferr)
{
if(data==0)
{
rx_state=wait_for_start;
}
else
{
rx_state=wait_for_next_byte;
}
}
else
{
// keep track of the number of bytes received so that we will know when to
// start receiving data
dmx_512_count++;
if(dmx_512_count == dmx_512_offset)
{
rx_state=receive_data;
}
}
break;
/*******************************************************/
case receive_data:
// check for framing error - if we receive a framing error then this might
// be the beggining of a new packet or a true framing error
if(rcsta.bits.ferr)
{
// if this is the beginning of the next frame then data must be 0
// else this is a framing error
if(!data)
rx_state=wait_for_start;
else
rx_state=wait_for_next_byte;
}
else
{
level=data; // store the data received in ' level '
// our 'level' has been found so wait for break
rx_state=wait_for_break;
}
}
}
led=1; // reception led off;
return;
} |
I found something very interesting though. The code did not work right in my board. I had tested some code for someone using a 16F786A REV B0 chip. I normally use just the 16F876. I discovered that the Framing Error bit does not get cleared! I couldn't clear it no matter what I did except a reset. RJ Hamlett had problems clearing this bit and recommended doing the same method used to clear an overrun error. This also didn't work. There is also a post on Microchips forum with the same issue. You might do a little test if you still cannot get it to work by putting a check after:
Code: | while(rcif)
{
led=0; // reception led on;
rcsta.bte=RCSTA; // copy rx status reg
data=rcreg;
if (bit_test(RCSTA,2))
{
// This bit should not be set here since we just read the data
// well actually it could if the next byte also has a framing error
}
|
|
|
|
davt
Joined: 07 Oct 2003 Posts: 66 Location: England
|
|
Posted: Tue Nov 02, 2004 10:19 am |
|
|
Mark
I noticed in the case statement - wait_for_data there is:
if(dmx_512_count == dmx_512_offset)
{
rx_state=receive_data;
}
but no ' else '
should it be:
if(dmx_512_count == dmx_512_offset)
{
rx_state=receive_data;
}
else
{
rx_state=wait_for_data;
}
to get the next data byte and loop through all 512 channels until there is a match is a match?
Regards
Dave |
|
|
Mark
Joined: 07 Sep 2003 Posts: 2838 Location: Atlanta, GA
|
|
Posted: Tue Nov 02, 2004 11:17 am |
|
|
rx_state is already = receive_data so it is not really necessary.
I noticed that you had:
Code: | unsigned int16 dmx_512_offset; // channel number??
|
If you haven't figured out what the offset is, let me explain. The PIC I orginally used didn't have enough RAM for all the DMX levels. We use the device as a DMX interface into our system. The offset simply starts reading the channels at the specified offset. If you are only conerned with the first # of channels, the offset could be removed. |
|
|
Mark
Joined: 07 Sep 2003 Posts: 2838 Location: Atlanta, GA
|
|
Posted: Tue Nov 02, 2004 11:29 am |
|
|
One more thing:
should actually be
Code: | #bit rxd9 = RCSTA.0
|
which is the data. For 9bit receive
Also, for DMX you should use 8 bit. |
|
|
davt
Joined: 07 Oct 2003 Posts: 66 Location: England
|
|
Posted: Wed Nov 03, 2004 8:21 am |
|
|
Thanks for the input Mark
I have set the usart to 8 bit receive and amended the bit rx9 problem.
The routine is still not working - frustration is setting in.
I have been through the routine many times now and cannot see where the problem is. I am trying to follow the flow of the state machine with my test pins and scope - but I feel I a brick wall rapidly aproaching!!
Any more ideas?
Sorry if I am a pest.
Dave |
|
|
Mark
Joined: 07 Sep 2003 Posts: 2838 Location: Atlanta, GA
|
|
Posted: Wed Nov 03, 2004 8:28 am |
|
|
Did you add the #case? You should have gotten an error on one of the #defines due to capitalization. The will also fix the problem with the rcsta reg.
Are you using an ICD to debug? If so,
Code: |
while(rcif)
{
led=0; // reception led on;
rcsta.bte=RCSTA; // copy rx status reg
data=rcreg;
if (bit_test(RCSTA,2))
{
// Put something in here and set a break point or maybe toggle an LED
}
|
This will tell us if the UART has the problems that I saw with the 16F876A.
What did you do with the receive enable pin of the 485 transceiver? |
|
|
Guest
|
Help |
Posted: Mon Dec 27, 2004 6:28 pm |
|
|
Any ideas on what's wrong?
Code: | #if defined(__PCH__)
#include <18F8720.h>
#fuses HS
#use delay(clock=20000000)
#USE STANDARD_IO(D)
#endif
#case
#byte SPBRG2 = 0xF6F
#byte RCSTA2 = 0xF6B
#byte TXSTA2 = 0xF6C
#byte RCREG2 = 0xF6E
#byte TXREG2 = 0xF6D
#byte TRISG = 0xF98
#byte PIR3 = 0xFA4
#bit SPEN = RCSTA2.7
#bit RX9 = RCSTA2.6
#bit SREN = RCSTA2.5
#bit CREN = RCSTA2.4
#bit ADDEN = RCSTA2.3
#bit FERR = RCSTA2.2
#bit OERR = RCSTA2.1
#bit RX9D = RCSTA2.0
#bit BRGH = TXSTA2.2
#bit SYNC = TXSTA2.4
#bit TRISG1 = TRISG.1
#bit TRISG2 = TRISG.2
#bit RC2IF = PIR3.5
int i;
unsigned int DMX_512_Offset = 0;
unsigned int Rx_Buffer[40];
unsigned int MAX_BUFFER = 40;
unsigned char levels;
#INT_RDA
void Interrupt_USART_Rx(void)
{
#define WAIT_FOR_NEXT_BYTE 0
#define WAIT_FOR_BREAK 1
#define WAIT_FOR_START 2
#define WAIT_FOR_DATA 3
#define RECEIVE_DATA 4
union
{
unsigned char byte;
struct {
unsigned char RX9D:1;
unsigned char OERR:1;
unsigned char FERR:1;
unsigned char ADDEN:1;
unsigned char CREN:1;
unsigned char SREN:1;
unsigned char RX9:1;
unsigned char SPEN:1;
} bits ;
}rcsta2;
/* Data that we are receiving */
char data;
/* State machine for determining the begining of the DMX stream */
static char Rx_State = WAIT_FOR_BREAK;
/* Duplicate of the RCSTA reg used due to the double buffering of the
fifo. Reading the RCREG reg will cause the second RCSTA reg to be
loaded if there is one. */
/* DMX frame counter */
static unsigned int DMX_512_Count = 0;
/* receive buffer index */
static char Rx_Index = 0;
/* Keep reading the data so long as it is present. */
while (RC2IF)
{
/* Read the data and the Rx status reg */
rcsta2.byte = RCSTA2;
data = RCREG2;
/* Check for buffer overrun error */
if (rcsta2.bits.OERR)
{
// rcsta2.bits.CREN = 0;
// rcsta2.bits.CREN = 1;
CREN = 0;
CREN = 1;
/* we just received a buffer overrun so lets wait
for a good data byte before we look for the break signal. */
Rx_State = WAIT_FOR_NEXT_BYTE;
return;
}
switch (Rx_State)
{
case WAIT_FOR_NEXT_BYTE:
if (!rcsta2.bits.FERR)
Rx_State = WAIT_FOR_BREAK;
break;
case WAIT_FOR_BREAK:
/* Check for a framing error */
if (rcsta2.bits.FERR)
{
/* If we did receive a framing error, make sure that the data is 0.
This means that we did Rx the break signal for at least 44us. */
if (!data)
Rx_State = WAIT_FOR_START;
}
break;
case WAIT_FOR_START:
/* Check for a framing error. If we receive one then we need to wait
until we receive a good data byte before we begin looking for our
Break signal */
if (rcsta2.bits.FERR)
Rx_State = WAIT_FOR_NEXT_BYTE;
/* The start code for our data packet should always start with 0. */
else
{
if (!data)
{
/* Initialize our index to our Rx buffer. */
Rx_Index = 0;
/* Here we determine where in the DMX stream we should begin
receiving data based on our DMX offset address. */
if (DMX_512_Offset == 1)
Rx_State = RECEIVE_DATA;
else
{
Rx_State = WAIT_FOR_DATA;
DMX_512_Count = 1;
}
}
else
{
Rx_State = WAIT_FOR_BREAK;
}
}
break;
case WAIT_FOR_DATA:
/* Check for a framing error. If we receive one then we need to wait
until we receive a good data byte before we begin looking for our
Break signal */
if (rcsta2.bits.FERR)
{
/* This could be a break signal indicating the start of the DMX stream */
if (!data)
Rx_State = WAIT_FOR_START;
else
Rx_State = WAIT_FOR_NEXT_BYTE;
}
else
{
/* Keep track of the number of bytes received so that we will know
when to start receiving the data */
DMX_512_Count++;
if (DMX_512_Count == DMX_512_Offset)
Rx_State = RECEIVE_DATA;
}
break;
case RECEIVE_DATA:
/* check for framing error - if we receive a framing error then this
might be the begining of the next packet or a true framing error. */
if (rcsta2.bits.FERR)
{
/* if this is the beginging of the next frame then data must = 0
else this is a framing error. */
if (!data)
Rx_State = WAIT_FOR_START;
else
Rx_State = WAIT_FOR_NEXT_BYTE;
}
else
{
/* Store the data received in the Rx buffer */
// if (Rx_Buffer[Rx_Index] != data)
// levels[Rx_Index] |= 0x80;
Rx_Buffer[Rx_Index] = data;
/* Point to the next byte */
++Rx_Index;
/* Check to see if we have received all of our data */
// if (Rx_Index >= MAX_BUFFER)
// Rx_State = WAIT_FOR_BREAK;
}
break;
/* Unknown start code */
}
}
return;
}
int main () {
// configure USART2 RS-485 250kbps with 20MHz osc
SPEN = 1; // 1 = Serial port enabled
TRISG1 = 0;
TRISG2 = 1;
SPBRG2 = 0x04;
BRGH = 1;
SYNC = 0;
RX9 = 0; // 1 = Selects 9-bit reception
CREN = 1; // 1 = Enables continuous receive
ADDEN = 0; // 1 = Enables address detection
FERR = 1; // 1 = Framing error
OERR = 1; // 1 = Overrun error
enable_interrupts(GLOBAL);
enable_interrupts(INT_RDA);
Interrupt_USART_Rx();
while (1) {
// for (i=0; i<=35; i++)
output_d(Rx_Buffer[5]);
}
return (0);
} |
Thank you, Jerry |
|
|
Mark
Joined: 07 Sep 2003 Posts: 2838 Location: Atlanta, GA
|
|
Posted: Mon Dec 27, 2004 8:57 pm |
|
|
Code: | #INT_RDA
void Interrupt_USART_Rx(void) |
It looks like you want to use the other int so the above is the wrong isr handler use this one
|
|
|
Guest
|
|
Posted: Mon Dec 27, 2004 10:19 pm |
|
|
Unfortunately, there's no such command CCS.
In Microchip's C18 the following would work:
Code: | /* For high interrupts, control is transferred to address 0x8.*/
void Interrupt_USART_Rx (void); /* prototype needed for 'goto' below */
#pragma code HIGH_INTERRUPT_VECTOR = 0x8
void high_ISR (void)
{
_asm
goto Interrupt_USART_Rx
_endasm
}
#pragma code /* allow the linker to locate the remaining code */
#pragma interrupt Interrupt_USART_Rx
void Interrupt_USART_Rx (void) {
...
}
|
Is there an equivalent in CCS?
Thanks, Jerry |
|
|
|