How to claim address in J1939 protocol - c

Hello I'm trying to read remaining capacity information of some battery which sends some informations with J1939 protocol. For that I am using PIC18F26K83, so as I have understood before I want to send data to battery to show that I want some spesific information I need to take address. However when I try to claim address from PGN 60928, transmission never occurs. Everything looks correct but TXREQ bit never gets zeroed.Related part of the code can be seen below:
PS: In hardware wise everything is fine I have 2 nodes which is enough for can bus and I put 120 ohm resistor between my Can transsiver Rx and Tx etc.
So my question is: for implementing J1939 protocol is it a necessity to claim an address even if it will not be used in the real vehicles system and are there any required steps before claiming an address? Just setting up the can bus and putting it into the normal mode and transmitting the name data to PGN 60928 would be enough?
//Address Claim
TXB0CON= 0b00000011; //Priority 0 clear TXREQ
//Sender ID in Extended Form
//PGN 60928 = 0b1110111000000000 (Address Claim)
TXB0SIDH= 0b11000111; //EID <28-1> Priority =6
TXB0SIDL= 0b01101010; //Extended Enable
TXB0EIDH= 0b00000000; //
TXB0EIDL= 0X80; //Source ID=128;
TXB0DLC = 0b00001000; //No RTR Data Length=
//Data to be sent
TXB0D0=0X80;
TXB0D1=0XFE;
TXB0D2=0XFF;
TXB0D4=0XFF;
TXB0D5=0XFF;
TXB0D6=0XFF;
TXB0D7=0XFF;
//Normal Mode
CANCON =0x00;
while(!(CANCON.B7==0 && CANCON.B6 ==0 && CANCON.B5==0)){
LATA2_BIT=1;
} // Wait for can to enter normal mode
LATA2_BIT=0;
TXB0CON = 0b00001011; //transmission request , priority 0
wait: if(TXB0CON.B3==1){
LATA2_BIT =1;
goto wait;} //Wait until Transmission is Succesfull

Filters might be a problem, set mask to 0x00 and try again

Related

Mixed voltage reading from different AD7606 channels

Please help! I am using FSMC to connect a STM32F407 MCU with AD7606 to sample voltage value. MCU would send sampled values to PC using USB HS port after 1024 conversions. But when I inspect the values from PC, I found that readings from channel 0 occasionally contains data from other channels. For example, if connect channel 0 to 5v, connect channel 8 to 3.3v, connect other channels to ground. Then the printed value from channel 0 would contain 5v, 0v, 3.3v. The basic setup is as follows:
A 200KHZ PWM single is generated by TIM10 to act as CONVST signal for AD7606.
7606 will then issue a BUSY signal which I used as an external interrupt source.
In the Interrupt handler, An DMA request would be issued to read 8 16bit data
from FSMC address space to memory space. TIM10 PWM would be stopped if 1024
conversions has been done.
In the DMA XFER_CPLT call back, if 1024 conversions has been done, the converted
data would be sent out by USB HS port, and TIM10 PWM would be enabled again.
Some code blocks:
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
if(GPIO_Pin == GPIO_PIN_7)
{
// DMA data from FSMC to memory
HAL_DMA_Start_IT(&hdma_memtomem_dma2_stream0, 0x6C000000, (uint32_t)(adc_data + adc_data_idx) , 8);
adc_data_idx += 8;
if (adc_data_idx >= ADC_DATA_SIZE)
HAL_TIM_PWM_Stop(&htim10, TIM_CHANNEL_1);
}
}
void dma_done(DMA_HandleTypeDef *_hdma)
{
int i;
int ret;
// adc_data[adc_data_idx] would always contain data from
// channel 1, led1 wouldn't light if every thing is fine.
if (adc_data[adc_data_idx] < 0x7f00 )
HAL_GPIO_WritePin(led1_GPIO_Port, led1_Pin, GPIO_PIN_SET);
if (adc_data_idx >= ADC_DATA_SIZE)
{
if(hUsbDeviceHS.dev_state == USBD_STATE_CONFIGURED)
{
// if I don't call CDC_Transmit_HS, everything is fine.
ret = CDC_Transmit_HS((uint8_t *)(adc_data), ADC_DATA_SIZE * 2 );
if (ret != USBD_OK)
{
HAL_GPIO_WritePin(led1_GPIO_Port, led2_Pin, GPIO_PIN_SET);
}
}
adc_data_idx = 0;
HAL_TIM_PWM_Start(&htim10, TIM_CHANNEL_1);
}
}
It seems that a single USB transaction would take longer than 5us(one conversion time), so I stopped PWM signal to stop conversion...
If I only send the second half of the data buffer, there is no data mixture. It's very strange.
According to your description, I think the processing is correct, and the problem is at the CDC_Transmit_HS(); I have met the problem on the CDC_Transmit_FS(), which can't transmit more than 64 bytes data for original code, and need to modify some code, otherwise the some error occurs. Did you check the number of received data is correct?
Reference:
I can't receive more than 64 bytes on custom USB CDC class based STM32 device
I'm not sure your ADC_DATA_SIZE size; if it's larger than 64 bytes, maybe you can modify to smaller than 64 bytes and try again and check whether or not the data is correct. I am not sure if it is affected by this problem, but I think you can give it a try.
On the other hand, it may also be necessary to GND the ADC IN pins not used by AD7606 to avoid interference between channels.
Or you can try other communication (I2C, SPI, UART...etc) to send the data.
If there is no problem with other communication methods, there is a high chance that it is a problem with CDC_Transmit_HS(). If there are problems with other transmission methods, you may have to check whether there is a conflict between the ADC conversion time or the transmission time.

Tiva C cannot change value of MDR register

i have a tiva c micro controller the tm4c123gxl and i have been trying for a while now to use the I2C module on the board with a digital accelrometer with no result , i have been trying to set the MDR register with a certain value to send but it stays as 0
here is the code i am using for intialization till reaching part where i set the MDR register im using step by step debugging i run the code initially to the assignment step of I2C3_MDR_R = 0x2D;
void PortDInit(void)
{
volatile unsigned long delay=0;
SYSCTL_RCGCI2C_R|=0x8; //1-set clock of I2C of module 3
delay = SYSCTL_RCGC2_R; //2-delay to allow clock to stabilize
SYSCTL_RCGC2_R |= 0x00000008; //3-port D clock
delay = SYSCTL_RCGC2_R; //4-delay to allow clock to stabilize
GPIO_PORTD_AFSEL_R |= 0x03; //5-alternate function set for I2C mode
GPIO_PORTD_DEN_R |=0x03; //6-enable digital functionality for PA6 and PA7
GPIO_PORTD_ODR_R|=0x02; //7-enable open drain mode for I2CSDA register of port A
GPIO_PORTD_PCTL_R = 0x00000033; //8-set PCTL to I2C mode
I2C3_MCR_R= 0x00000010; // 9-intialize the i2c master
I2C3_MTPR_R = 0x00000007; // 10-number of system clock cycles in 1 scl period
I2C3_MSA_R = 0x3A // set slave address and read write bit
I2C3_MDR_R = 0x2D; // data to be sent BREAK POINT HERE using single step here yields MDR with same value = 0
I2C3_MCS_R = 0x00000003; // follow transmit condition
while(I2C3_MCS_R &= 0x40 == 1); // wait bus is busy sending data
if(I2C3_MCS_R&=0x04 ==1)
{
//handle error in communication
}
else
{
//success in transmission
}
what i have done to reach this code
carefully understood the I2C protocol how it works etc.
check the data sheet and follow the initalization steps mentioned there step by step which got me to this code
i know i should use tivaware library which will be easier but using
the registers helps me understand more of how everything is working ,
im still a student
at first i didnt have the digital enable line as it wasnt mentioned
to be activated for the I2C but its only logical it should be there
as we are using digital values i tried with both yielded the same
output mdr=0
i am using keil 4 as my IDE and im viewing the values of registers of
I2C module 3 to know whether data is placed in MDR or not
hope any one helps
thanks.
This is a long shot, but here goes:
in your comments, step 6 says
//6-enable digital functionality for PA6 and PA7
but it appears you are working on GPIO_PORTD...
maybe its a comment typo (you meant PD6 and PD7)
but just double check you are looking at the right pins...
Good luck!

PIC16F1459 I2C Master Ack Issue with 24LC32

I'm facing a weird issue. I've always used bit bangin I2C functions on my PIC16F1459, but now I want to use the MSSP (SPI,I2C Master Slave Peripheral). So I've started writing the functions according to the datasheet, Start, Stop, etc. The problem I have is my PIC won't ACK the data I send to the I2C EEPROM. It clearly says in the datasheet that the ACK status can be found at SSPCON2.ACKSTAT. So my guess was to poll this bit until the slave responds to my data, but the program hangs in the while Loop.
void vReadACK (void)
{
while (SSPCON2.ACKSTAT != 0);
}
And here's my write function, my I2CCheck function and I2C Master Initialization function
void vI2CEcrireOctet (UC ucData, UC ucRW)
{
vI2CCheck();
switch (ucRW)
{
case READ:
SSPBUF = ucData + 1;
break;
case WRITE:
SSPBUF = ucData + 0;
break;
}
vReadACK();
}
void vI2CCheck (void)
{
while (SSPCON2.ACKEN); //ACKEN not cleared, wait
while (SSPCON2.RCEN); //RCEN not cleared, wait
while (SSPCON2.PEN); //STOP not cleared, wait
while (SSPCON2.SEN); //Start not cleared, wait
while (SSPCON2.RSEN); //Rep start not cleared, wait
while (SSP1STAT.R_NOT_W); //TX not done wait
}
void vInitI2CMaster (void)
{
TRISB4_bit = 1; //SDA IN
TRISB6_bit = 1; //SCL IN
SSP1STAT.SMP = 1; //No slew rate
SSP1STAT.CKE = 0; //Disable SMBus inputs
SSPADD = 0x27; //100 KHz
SSPCON1 = 0b00101000; //I2C Master mode
SSPCON3 = 0b00000000; //Rien de slave
}
Just so you know, 24LC32A WriteProtect tied to VSS, A2-A1-A0 tied to GND, so adress 0xA0. 4k7 pull-ups are on I2C line. PIC16F1459 at 16MHz INTOSC.
I'm completely stuck. I've went through the MSSP datasheet 5 to 6 times without finding any issue. Can you guys help?
And here's my logic analyzer preview (removing the while inside vReadAck() )
Well it looks like I've found the answer to my question. What I was doing was the exact way of doing this. The problem seemed to be the Bus Free Time delay required for the slave to respond. At 16Mhz, my I2C was probably too fast for the EEPROM memory. So I've added a small Delay function right after the stop operation, so the write sequences are delayed and BAM, worked.
Bus free time: Time the bus
must be free before a new
transmission can start.
Despite the fact you "totally know" know "PIC won't ACK the data I send to the I2C EEPROM" because it's not supposed to, you still seem to misunderstand how I2C acknowledgements are supposed to work. They're called acknowledgements because they can be both positively (ACK) and negatively (NAK) acknowledged. If you look at the the analyzer screen shot you posted you'll find that its quite clearly labelled each byte being sent as having been NAK'ed by the transmitter.
To properly check for I2C ACKs you should be polling the trailing edge of the ACKTIM bit, and then checking the ACKSTAT bit to find out whether the slave transmitted an ACK or a NAK bit. Something like this:
int
vReadACK() {
while(!SSPCON3.ACKTIM);
while(SSPCON3.ACKTIM);
return SSPCON2.ACKSTAT;
}
As for why your slaved device is apparently NAKing each byte it isn't clear from the code you've posted, but there's a couple of notable omissions from your code. You need to generate start and stop conditions but you've shown no code to do this.

pic32 start bit does not clear -- Basic I2C setup

I am new to embedded programming and am trying to get my first I2C project working. I am using the PIC32MX795F512L. I am pretty much following the microchip datasheet for I2C on PIC32. The problem I'm having is the S bit is never cleared from the I2C1STAT register. It is actually unclear to me whether I have to do this or if it is done automatically at the conclusion of the Start event, but right now I'm trying to manually clear it. However, nothing that I do seems to have an effect. If more information is needed to make it easier to understand what is happening let me know. I am using a PICKIT3 so I can get debugging information as well. I know that the Master interrupt occurs, the S bit gets set, I exit the interrupt code and hang on the while statement checking the I2C1STATbits.S.
Edit: I'm editing this post to have my new code instead of the old code. I am now using a 20MHZ peripheral clock. Just one of the many things I tried today that did not work. Delay is just a 256ms delay. Super long I know, but it was quick.
main()
{
//Setup I2C1CON
I2C1CONbits.SIDL = 0; //Continue to run while in Idle
I2C1CONbits.SCLREL = 1; //Release the clock (Unsure of this)
I2C1CONbits.A10M = 0; //Using a 7 bit slave address
I2C1CONbits.DISSLW = 1; //Slew rate control disabled because running at 100 KHZ
I2C1ADD = 0x1E; //Slave address without read or write bit
I2C1BRG = 0x060; //Set the BRG clock rate - Based on Page 24-19
I2C1CONbits.ON = 1; //Turn on the I2C module
delay();
I2C1CONbits.SEN = 1; //Initiate a start event
while(I2C1CONbits.SEN == 1); //Wait until Start event is done
I2C1TRN = 0x3C; //Load the address into the Transmit register
while(I2C1STATbits.TRSTAT == 1);
while(I2C1STATbits.ACKSTAT == 0); //Wait for a ACK from the device
I2C1TRN = 0x00;
while(I2C1STATbits.TRSTAT == 1);
while(I2C1STATbits.ACKSTAT == 0);
I2C1TRN = 0x70;
while(I2C1STATbits.TRSTAT == 1);
while(I2C1STATbits.ACKSTAT == 0);
while(1);
}
Thanks for any help.
I'm also just beggining on PIC32MZ family, setting up the I2C to talk to various memory chips.
I used your code and modified it so that it would work properly. Since I am using PIC32MZ family, I believe the I2C registers should probably be the same.
I2C configuration:
I2C1CONbits.SIDL = 0; // Stop in Idle Mode bit -> Continue module operation when the device enters Idle mode
I2C1CONbits.A10M = 0; // 10-bit Slave Address Flag bit -> I2CxADD register is a 7-bit slave address
I2C1CONbits.DISSLW = 1; // Slew Rate Control Disable bit -> Slew rate control disabled for Standard Speed mode (100 kHz)
I2C1CONbits.ACKDT = 0; // Acknowledge Data bit -> ~ACK is sent
I2C1BRG = 0x0F3; // Baud Rate Generator set to provide 100KHz for SCL with 50 MHz xtal.
I followed the transmission steps provided in the I2C Datasheet so it would be easy to follow the steps coupled with the pdf and my comments on the code.
I2C Data Transmission:
// 1. Turn on the I2C module by setting the ON bit (I2CxCON<15>) to ‘1’.
I2C1CONbits.ON = 1; // I2C Enable bit -> Enables the I2C module and configures the SDAx and SCLx pins as serial port pins
//------------- WRITE begins here ------------
// 2. Assert a Start condition on SDAx and SCLx.
I2C1CONbits.PEN = 0; // Stop Condition Enable Bit -> Stop Condition Idle
I2C1CONbits.SEN = 1; // Start Condition Enable bit -> Initiate Start condition on SDAx and SCLx pins; cleared by module
while(I2C1CONbits.SEN == 1); // SEN is to be cleared when I2C Start procedure has been completed
// 3. Load the Data on the bus
I2C1TRN = 0b10100000 ; // Write the slave address to the transmit register for I2C WRITE
while(I2C1STATbits.TRSTAT == 1); // MASTER Transmit still in progress
while(I2C1STATbits.ACKSTAT == 1); // Master should receive the ACK from Slave, which will clear the I2C1STAT<ACKSTAT> bit.
I2C1TRN = 0xCE; // Register Address
while(I2C1STATbits.TRSTAT == 1);
while(I2C1STATbits.ACKSTAT == 1);
I2C1TRN = 0xCF; // Register Value
while(I2C1STATbits.TRSTAT == 1);
while(I2C1STATbits.ACKSTAT == 1);
I2C1CONbits.PEN = 1; // Stop Condition Enable Bit -> Initiate Stop condition on SDAx and SCLx pins; cleared by module
//-------------- WRITE ends here -------------
This code works well as I used a couple of LEDs to toggle indicating a successful write procedure.
The while(!(I2C1STATbits.ACKSTAT == 0)); is the right way i guess.I2C1ADD is used to set the slave address of the current PIC mc if you are using your I2C as slave.If any master requests start with that slave address the PIC will respond to that as slave.
Read this pdf where initially they have specified that in PIC the I2C is configured as both master and slave and the master request is checked by the same PIC with with the slave address in the I2C1ADD value.
http://ww1.microchip.com/downloads/en/DeviceDoc/61116F.pdf

Receiving SPI data via DMA on PIC32

I know that this topic (DMA & SPI) has already been talked about on numerous threads in the microchip forum, actually i've read all the 15 pages in result of the search with keyword "dma" and read all the topics about dma & spi.
And I am still stuck with my problem I hope someone can help me :)
Here is the problem.
My chip is a PIC32MX775F512H.
I am trying to receive (only receive) data using SPI via DMA.
Since you cannot "just" receive in SPI, and that the SPI core starts toggling the SPI clock only if you write into the SPIBUF (SPI1ABUF for me) I am trying to receive my data using 2 DMA channels.
DMA_CHANNEL1 for the transmitting part.
DMA_CHANNEL2 for the receiving part.
I copy pasted the code from http://www.microchip.com/forums/tm.aspx?tree=true&high=&m=562453&mpage=1#
And tried to make it work without any luck. It only receives several bytes (5 or 6).
I've set the Event Enable Flags to DMA_EV_BLOCK_DONE for both dma channels, no interrupt occurs.
Do you have any idea ?
Here is the code I am using :
int Spi_recv_via_DMA(SPI_simple_master_class* SPI_Port, int8u *in_bytes, int16u num_bytes2)
{
DmaChannel dmaTxChn=DMA_CHANNEL1;
DmaChannel dmaRxChn=DMA_CHANNEL2;
SpiChannel spiTxChn=SPI_Port->channel;
int8u dummy_input;
DmaChnOpen(dmaTxChn, DMA_CHN_PRI3, DMA_OPEN_DEFAULT);
DmaChnOpen(dmaRxChn, DMA_CHN_PRI3, DMA_OPEN_DEFAULT);
DmaChnSetEventControl(dmaTxChn, DMA_EV_START_IRQ_EN | DMA_EV_START_IRQ(_SPI1A_RX_IRQ));
DmaChnSetEventControl(dmaRxChn, DMA_EV_START_IRQ_EN | DMA_EV_START_IRQ(_SPI1A_RX_IRQ));
DmaChnClrEvFlags(dmaTxChn, DMA_EV_ALL_EVNTS);
DmaChnClrEvFlags(dmaRxChn, DMA_EV_ALL_EVNTS);
DmaChnSetEvEnableFlags(dmaRxChn, DMA_EV_BLOCK_DONE);
DmaChnSetEvEnableFlags(dmaTxChn, DMA_EV_BLOCK_DONE);
//SpiChnClrTxIntFlag(spiTxChn);
//SpiChnClrRxIntFlag(spiTxChn);
DmaChnSetTxfer(dmaTxChn, tx_dummy_buffer, (void *)&SPI1ABUF, num_bytes2, 1, 1);
DmaChnSetTxfer(dmaRxChn, (void *)&SPI1ABUF, in_bytes, 1, num_bytes2, 1);
while ( (SPI1ASTAT & SPIRBE) == 0)
dummy_input = SPI1ABUF;
SPI1ASTAT &= ~SPIROV;
DmaRxIntFlag = 0;
DmaChnEnable(dmaRxChn);
DmaChnStartTxfer(dmaTxChn, DMA_WAIT_NOT, 0);
while(!DmaRxIntFlag);
return 1;
}
with those two interrupt handlers :
// handler for the DMA channel 1 interrupt
void __ISR(_DMA1_VECTOR, ipl5) DmaHandler1(void)
{
int evFlags; // event flags when getting the interrupt
//LED_On(LED_CFG);
INTClearFlag(INT_SOURCE_DMA(DMA_CHANNEL1)); // acknowledge the INT controller, we're servicing int
evFlags=DmaChnGetEvFlags(DMA_CHANNEL1); // get the event flags
if(evFlags&DMA_EV_BLOCK_DONE)
{ // just a sanity check. we enabled just the DMA_EV_BLOCK_DONE transfer done interrupt
DmaTxIntFlag = 1;
DmaChnClrEvFlags(DMA_CHANNEL1, DMA_EV_BLOCK_DONE);
}
// LED_Off(LED_CFG);
}
void __ISR(_DMA2_VECTOR, ipl5) DmaHandler2(void)
{
int evFlags; // event flags when getting the interrupt
INTClearFlag(INT_SOURCE_DMA(DMA_CHANNEL2)); // acknowledge the INT controller, we're servicing int
evFlags=DmaChnGetEvFlags(DMA_CHANNEL2); // get the event flags
if(evFlags&DMA_EV_BLOCK_DONE)
{ // just a sanity check. we enabled just the DMA_EV_BLOCK_DONE transfer done interrupt
DmaRxIntFlag = 1;
DmaChnClrEvFlags(DMA_CHANNEL2, DMA_EV_BLOCK_DONE);
}
}
So I end up waiting forever at the line : while(!DmaRxIntFlag);
I have put breakpoints in the interrupt vectors, they are never called.
This is the state of several registers during the ever lasting wait :
DMACON 0x0000C800
DMASTAT 0x00000001
I am using SPI1A port, so SPI1ABUF and _SPI1A_RX_IRQ
DCH1SPTR 0x5
DCH1SSIZ 0x2B
DCH2DPTR 0x6
DCH2DSIZ 0x2B
DCH2CON 0x00008083
DCH2ECON 0x1B10
DCH2INT 0x00800C4
DCH2SSA 0x1F805820
DCH2DSA 0x00000620
Channel 1 is used to transmit
Channel 2 is used to receive
You are missing these:
INTEnable(INT_SOURCE_DMA(dmaTxChn), INT_ENABLED); // Tx
INTEnable(INT_SOURCE_DMA(dmaRxChn), INT_ENABLED); // Rx
rigth before
DmaRxIntFlag = 0;
DmaChnEnable(dmaRxChn);
DmaChnStartTxfer(dmaTxChn, DMA_WAIT_NOT, 0);
Good luck!
Are you using the SPI in slave mode? or you are on master mode, trying to read some response for a command?
Have you check the silicon errata for this chip? The dspic 33fj family had an issue where SPI slave mode simply didn't work.
Other than that, I don't think it is a good idea to busy wait for DmaRxIntFlag change. You should configure the DMA transfer and continue with your main loop. The DMA will trigger the interrupt handler.
Hope this helps.

Resources