Transport protokoll i J1939-21 - Hur gör man för skicka 9 bytes?

PIC, AVR, Arduino, Raspberry Pi, Basic Stamp, PLC mm.
DanielM
Inlägg: 2166
Blev medlem: 5 september 2019, 14:19:58

Re: Transport protokoll i J1939-21 - Hur gör man för skicka 9 bytes?

Inlägg av DanielM »

mrfrenzy skrev: 13 augusti 2020, 07:16:32 Det är lite förvirrande språk.
Den texten betyder att dom förutsätter att din ECU har adress 0x22.
ACU tar emot meddelanden FRÅN alla adresser
ACU skickar bara TILL adress 0x22 även om frågan kom från en annan adress.

Om du ska skicka ett meddelande från ECU till ACU blir SA=0x22 och DA=0x80.
När ACU skickar ett meddelande til ECU blir SA=0x80 och DA=0x22

Om din ECU skulle ha adress 0x11 så kommer ACU (felaktigt) ta emot ett meddelande med SA=0x11 och DA=0x80
Svaret kommer den skicka med SA=0x80 och DA=0x22 så du kommer aldrig se det.
Jag sätter att min ECU har 0x22 som adress. Hur jag sätter det? Jag bara skriver in 22 som SA för ECU i ID-meddelandet.
Än fast ACU skickar endast till 0x22 så kan jag läsa exakt alla meddelanden på CAN-bus linan.

Med tanke på att jag kan göra Flow Control i J1939 så betyder det att jag kan faktiskt skicka meddelanden till ACU med 0x22. Men jag kunde även skicka meddelanden till ACU när jag satte ACU adressen till 0x8D av misstag.
hawkan skrev: 13 augusti 2020, 09:45:43 Här finns kod att titta på.
https://github.com/coryjfowler/MCP2515_lib som är j1939 utan att det nämns med ett ord (ojfr). Rad 600 finns en "write_id" man kan kolla hur de gör där.
copperhilltech.com har också massor om j1939. Källkod här http://copperhilltech.com/content/jCOM- ... e-Code.zip för exemplet här https://copperhilltech.com/blog/sae-j19 ... der-linux/
Inte exakt vad du frågar efter men om det är något fel du gör kanske koden kan hjälpa till för att jämföra.
Jag använder detta STM32 bibliotek. Fungerar utmärkt!
https://github.com/eziya/STM32_SPI_MCP2515

Så här ser ett mottagande och sändande för mig https://github.com/eziya/STM32_SPI_MCP2 ... Src/main.c

Jag läser den där CAN-bus C koden du länkande till. Jag finner att min CAN-bus kod, mottar meddelanden olika. Jag skickar alltså inte med någon prioritet.

Kod: Markera allt


uCAN_MSG txMessage;
uCAN_MSG rxMessage;

CANSPI_Initialize();	

while (1)
  {
  /* USER CODE END WHILE */

  /* USER CODE BEGIN 3 */
    if(CANSPI_Receive(&rxMessage))
    {
      txMessage.frame.idType = rxMessage.frame.idType;
      txMessage.frame.id = rxMessage.frame.id;
      txMessage.frame.dlc = rxMessage.frame.dlc;
      txMessage.frame.data0++;
      txMessage.frame.data1 = rxMessage.frame.data1;
      txMessage.frame.data2 = rxMessage.frame.data2;
      txMessage.frame.data3 = rxMessage.frame.data3;
      txMessage.frame.data4 = rxMessage.frame.data4;
      txMessage.frame.data5 = rxMessage.frame.data5;
      txMessage.frame.data6 = rxMessage.frame.data6;
      txMessage.frame.data7 = rxMessage.frame.data7;
      CANSPI_Transmit(&txMessage);
    }  
    
    txMessage.frame.idType = dSTANDARD_CAN_MSG_ID_2_0B;
    txMessage.frame.id = 0x0A;
    txMessage.frame.dlc = 8;
    txMessage.frame.data0 = 0;
    txMessage.frame.data1 = 1;
    txMessage.frame.data2 = 2;
    txMessage.frame.data3 = 3;
    txMessage.frame.data4 = 4;
    txMessage.frame.data5 = 5;
    txMessage.frame.data6 = 6;
    txMessage.frame.data7 = 7;
    CANSPI_Transmit(&txMessage);
    
    HAL_Delay(1000);
    
  }
DanielM
Inlägg: 2166
Blev medlem: 5 september 2019, 14:19:58

Re: Transport protokoll i J1939-21 - Hur gör man för skicka 9 bytes?

Inlägg av DanielM »

sodjan skrev: 13 augusti 2020, 09:55:45 Ah, OK... Så den DA som man anger i en ACU är inte ACU'ns egen DA, utan en förväntad adress för ECU'n.
Ja det förklarar ju allt. Sen så står det även att denna DA ändå inte används, i och för sig. ACU'n accepterar
meddelanden från vilken avsändare som helst i alla fall, men svarar alltid till 0x22 (eller sannolikt den
konfigurerade DA'n i ACU'n). Hade kanske varit tydligare om denna parameter hade kallats "ECU address"...

Men det betyder att man, rent teoretiskt, kan ändra DA i ACU och ha en annan adress än 0x22 på ECU (?).
Inte bara teoretiskt. Även praktiskt också via EEPROM. :)
DanielM
Inlägg: 2166
Blev medlem: 5 september 2019, 14:19:58

Re: Transport protokoll i J1939-21 - Hur gör man för skicka 9 bytes?

Inlägg av DanielM »

Tror ni jag ska ändra CA NAME något? Eller är det förprogrammerat och skall alltid vara så?
Användarvisningsbild
sodjan
EF Sponsor
Inlägg: 43149
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping
Kontakt:

Re: Transport protokoll i J1939-21 - Hur gör man för skicka 9 bytes?

Inlägg av sodjan »

> Men jag kunde även skicka meddelanden till ACU när jag satte ACU adressen till 0x8D av misstag.

Beror inte det på att ACU'n annonserar sin adress efter ett byte?
Så ECU'n vet att din ACU nu har adress 0x8D.

Som jag fattar det så är det enbart ECU som är fördefinierad till 0x22.
Resterande ACU'er annonserar sina adresser vid inkoppling (och reder
ut eventuella adress konflikter sinsemellan).
DanielM
Inlägg: 2166
Blev medlem: 5 september 2019, 14:19:58

Re: Transport protokoll i J1939-21 - Hur gör man för skicka 9 bytes?

Inlägg av DanielM »

Beror inte det på att ACU'n annonserar sin adress efter ett byte?
Så ECU'n vet att din ACU nu har adress 0x8D.
Vid start så blir det Claim Address. Då kan jag läsa utav denna kod här:

Kod: Markera allt

	        // Check what message we got
		if (id0 == 0x18 && id1 == 0xEE && id2 == 0xFF && id3 != 0xFE) {
			// Address claimed
			sbz->SA_ACU = id3;
			memcpy(sbz->CA, data, 8);
Min ECU är ju min STM32 och jag tror inte den vet att den har ECU addressen 0x22. Jag bara sätter 0x22 som adress när jag skriver ID meddelanden. Det kanske är förväntat från ACU att den ska få meddelanden från ECU som innehåller SA = 0x22.
Som jag fattar det så är det enbart ECU som är fördefinierad till 0x22.
Resterande ACU'er annonserar sina adresser vid inkoppling (och reder
ut eventuella adress konflikter sinsemellan).
Ja. Med tanke på att det är J1939 Function 0x81 (129d) i CA NAME, vilket betyder Auxiliary valve command 0...15. Detta betyder att om jag har 3 ACU, så numreras dom efter adresserna 0x30, 0x31, 0x32 osv. Jag behöver alltså inte sätta destinationsaddress i ID meddelandet. Jag tror detta du pratar om hela tiden. Lowest name?
Markering_071.png
Hela koden.

Kod: Markera allt

void read_sonceboz_status(SBZ* sbz) {
	// Check if we have connected the CAN
	if(CAN_connected == false){
		memset(sbz->CA, 0, 8);
		memset(sbz->errormessages_binary, 0, 12);
		sbz->SA_ACU = 0;
		CAN_connected = CANSPI_Initialize();
	}

	uint32_t ID;
	uint8_t data[8];
	if (read_j1939_message(&ID, data)) {
		uint8_t id0 = ID >> 24;
		uint8_t id1 = ID >> 16;
		uint8_t id2 = ID >> 8;
		uint8_t id3 = ID;
		// Check what message we got
		if (id0 == 0x18 && id1 == 0xEE && id2 == 0xFF && id3 != 0xFE) {
			// Address claimed
			sbz->SA_ACU = id3;
			memcpy(sbz->CA, data, 8);
		} else if (id0 == 0x18 && id1 == 0xEE && id2 == 0xFF && id3 == 0xFE) {
			// Address not claimed
			sbz->SA_ACU = 0;
			sbz->errormessages_binary[0] = true;
			memcpy(sbz->CA, data, 8);
		} else if (id0 == 0x18 && id1 == 0xFE && id2 == 0xCA && id3 == sbz->SA_ACU) {
			// DM1 message
			if (data[0] == 0x00 && data[1] == 0xFF && data[2] == 0x00 && data[3] == 0x00 && data[4] == 0x00 && data[5] == 0x00 && data[6] == 0xFF && data[7] == 0xFF) {
				// No error
			} else {
				// Error - Check only SPN and J1939 FMI:s - The rest are reserved
				uint8_t SPN_byte_3 = data[2];
				uint8_t SPN_byte_4 = data[3];
				uint8_t SPN_byte_5 = data[4] >> 5;
				uint8_t FMI_byte = data[4] & ~(0b11100000);
				if(SPN_byte_3 == 0x3F && SPN_byte_4 == 0xF0 && SPN_byte_5 == 0x7 && FMI_byte == 0x13){
					// Inconsistent CAN Control message
					sbz->errormessages_binary[1] = true;
				}else if(SPN_byte_3 == 0x3F && SPN_byte_4 == 0xF0 && SPN_byte_5 == 0x7 && FMI_byte == 0x9){
					// No CAN Control message received = TIME OUT
					sbz->errormessages_binary[2] = true;
				}else if(SPN_byte_3 == 0x74 && SPN_byte_4 == 0x2 && SPN_byte_5 == 0x0 && FMI_byte == 0x2){
					// EEPROM parameter write/read error
					sbz->errormessages_binary[3] = true;
				}else if(SPN_byte_3 == 0x40 && SPN_byte_4 == 0xF0 && SPN_byte_5 == 0x7 && FMI_byte == 0x0){
					// Stepper motor stall detected
					sbz->errormessages_binary[4] = true;
				}else if(SPN_byte_3 == 0x9E && SPN_byte_4 == 0x0 && SPN_byte_5 == 0x0 && FMI_byte == 0x12){
					// Undervoltage SONCEBOZ value (VDC<U_MINOFF)
					sbz->errormessages_binary[5] = true;
				}else if(SPN_byte_3 == 0x9E && SPN_byte_4 == 0x0 && SPN_byte_5 == 0x0 && FMI_byte == 0x10){
					// Overvoltage SONCEBOZ value (VDC>U_MAXOFF)
					sbz->errormessages_binary[6] = true;
				}else if(SPN_byte_3 == 0x42 && SPN_byte_4 == 0xF0 && SPN_byte_5 == 0x7 && FMI_byte == 0x0){
					// SCU temperature higher than T_MAXOFF
					sbz->errormessages_binary[7] = true;
				}else if(SPN_byte_3 == 0x42 && SPN_byte_4 == 0xF0 && SPN_byte_5 == 0x7 && FMI_byte == 0x1){
					// SCU temperature below T_MINOFF
					sbz->errormessages_binary[8] = true;
				}else if(SPN_byte_3 == 0x44 && SPN_byte_4 == 0xF0 && SPN_byte_5 == 0x7 && FMI_byte == 0x0){
					// Current exceeds upper limit I_MAX
					sbz->errormessages_binary[9] = true;
				}else if(SPN_byte_3 == 0x43 && SPN_byte_4 == 0xF0 && SPN_byte_5 == 0x7 && FMI_byte == 0x2){
					// Error position in IDLE Mode
					sbz->errormessages_binary[10] = true;
				}else if(SPN_byte_3 == 0x76 && SPN_byte_4 == 0x2 && SPN_byte_5 == 0x0 && FMI_byte == 0x2){
					// Range error for Linearization parameter in EEPROM
					sbz->errormessages_binary[11] = true;
				}
			}
		}
	}
}
Du har inte behörighet att öppna de filer som bifogats till detta inlägg.
Användarvisningsbild
sodjan
EF Sponsor
Inlägg: 43149
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping
Kontakt:

Re: Transport protokoll i J1939-21 - Hur gör man för skicka 9 bytes?

Inlägg av sodjan »

> Min ECU är ju min STM32 och jag tror inte den vet att den har ECU addressen 0x22. Jag bara sätter 0x22 som adress när jag skriver ID meddelanden.

Det som din ECU "vet" är ju exakt detsamma som det din kod gör. Det är ju samma sak.
Du sätter alltså 0x22 som "source address" då du skriver meddelanden. OK.

> Det kanske är förväntat från ACU att den ska få meddelanden från ECU som innehåller SA = 0x22.

Det sas tidigare att en ACU accepterar meddelanden från vilken adress som helst.
Men den svarar bara till 0x22.
DanielM
Inlägg: 2166
Blev medlem: 5 september 2019, 14:19:58

Re: Transport protokoll i J1939-21 - Hur gör man för skicka 9 bytes?

Inlägg av DanielM »

sodjan skrev: 13 augusti 2020, 14:00:22 Det som din ECU "vet" är ju exakt detsamma som det din kod gör. Det är ju samma sak.
Du sätter alltså 0x22 som "source address" då du skriver meddelanden. OK.
När jag skickar från ECU till ACU. Ja.
Det sas tidigare att en ACU accepterar meddelanden från vilken adress som helst.
Men den svarar bara till 0x22.
Jag har kollat igenom denna kod och den skickar korrekt data med korrekt indexering. Men jag tror att jag har glömt två saker. ACK + Request.
Tittar vi på denna hemsida. https://copperhilltech.com/blog/sae-j19 ... s-claimed/

Då ser vi att jag har glömt någon av dessa.
  • Request Message (PGN 59904)
    Address Claimed / Cannot Claim (PGN 60928)
    Cannot Claim Source Address (PGN 60928)
    Commanded Address (PGN 65240)
Idag utför jag inget Request Message eller ACK. Tror du jag måste göra detta?

Kod: Markera allt

static bool CAN_connected = false;
static uCAN_MSG txMessage;
static uCAN_MSG rxMessage;

// Write an extended CAN message
static void write_CAN_message(uint32_t ID, uint8_t data[]) {
	txMessage.frame.idType = dEXTENDED_CAN_MSG_ID_2_0B;
	txMessage.frame.id = ID;
	txMessage.frame.dlc = 8;
	txMessage.frame.data0 = data[0];
	txMessage.frame.data1 = data[1];
	txMessage.frame.data2 = data[2];
	txMessage.frame.data3 = data[3];
	txMessage.frame.data4 = data[4];
	txMessage.frame.data5 = data[5];
	txMessage.frame.data6 = data[6];
	txMessage.frame.data7 = data[7];
	CANSPI_Transmit(&txMessage);
}

// Read the extended  CAN message
static bool read_CAN_message(uint32_t* ID, uint8_t data[]){
	bool available = CANSPI_Receive(&rxMessage);
	if(available){
		//uint8_t idType = rxMessage.frame.idType; // Extended ID type
		*ID = rxMessage.frame.id;
		data[0] = rxMessage.frame.data0;
		data[1] = rxMessage.frame.data1;
		data[2] = rxMessage.frame.data2;
		data[3] = rxMessage.frame.data3;
		data[4] = rxMessage.frame.data4;
		data[5] = rxMessage.frame.data5;
		data[6] = rxMessage.frame.data6;
		data[7] = rxMessage.frame.data7;
		return available;
	}
	return available;
}

// Transport Protocol Connexion Management Broadcast Announce Message
static void send_j1939_TP_CM_BAM(SBZ* sbz, uint16_t message_size, uint8_t packages_to_send, uint32_t PGN){
	// ID
	uint32_t ID = (0x1CECFF << 8) | sbz->SA_ECU;

	// Fill the data
	uint8_t data[8];
	data[0] = 0x20; // Control byte - Standard
	data[1] = message_size; // Message size LSB. Total message size is 9 to 1785 bytes
	data[2] = message_size >> 8; // Message size MSB
	data[3] = packages_to_send; // Packages to send is 2 to 255 packages
	data[4] = 0xFF; // Reserved
	data[5] = PGN; // PGN LSB
	data[6] = PGN >> 8; // PGN
	data[7] = PGN >> 16; // PGN MSB

	// Write and wait 100 ms
	write_CAN_message(ID, data);
	HAL_Delay(100);
}

//Transport Protocol Data Transfer
static void send_j1939_TP_DT(SBZ* sbz, uint8_t data[], uint16_t message_size, uint8_t packages_to_send){
	uint32_t ID = (0x1CEBFF << 8) | sbz->SA_ECU;
	uint8_t package[8];
	uint16_t sended_bytes = 0;
	for(uint8_t i = 1; i <= packages_to_send; i++){
		// Number of package
		package[0] = i;

		// Data
		for(uint8_t j = 0; j < 7; j++){
			if(sended_bytes < message_size)
				package[j+1] = data[sended_bytes++];
			else
				package[j+1] = 0xFF; // No data
		}

		// Send wait 100 ms
		write_CAN_message(ID, package);
		HAL_Delay(100);
	}
}

// Write the new CA and SA
void write_1939_CA_names_and_source_address(SBZ* sbz){
	// Begin first to send BAM
	send_j1939_TP_CM_BAM(sbz, 0x9, 0x2, 0x00FED8); // 0x00FED8 = Commanded Address PGN

	// Send packages
	uint8_t data[9];
	memcpy(data, sbz->CA, 8); // Fill all CA to data
	data[8] = sbz->SA_ACU; // New address
	send_j1939_TP_DT(sbz, data, 0x9, 0x2);
}

// Write flow between -250 and 250. CA NAME need to have 0x81 (129d) Function code
void write_1939_auxiliary_valve_command(uint8_t DA, SBZ* sbz, float flow){
	uint8_t state;
	if (flow > 0) {
		state = 0x1; // Extend
	} else if (flow < 0) {
		state = 0x2; // Retract
	} else {
		state = 0x0; // Neutral
	}
	uint32_t ID = (0x0CFE << 16) | (DA << 8) | sbz->SA_ECU;
	uint8_t data[8] = {fabsf(flow), 0xFF, state, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
	write_CAN_message(ID, data);
}
DanielM
Inlägg: 2166
Blev medlem: 5 september 2019, 14:19:58

Re: Transport protokoll i J1939-21 - Hur gör man för skicka 9 bytes?

Inlägg av DanielM »

Jag har lyckats skapa kod för att anropa PGN 00EE00 (60928) (Address Claimed), alltså jag anropar den och då får jag CA NAMES tillbaka. Så det verkar som att det fungerar riktigt bra att anropa med Request PGN.

Tror ni att jag måste ta någon PGN request när jag ska ändra SA på ACU?

Kod:

Kod: Markera allt

// Connect can-bus, if we are not connected
static void connect_can_bus(J1939* j1939){
	if(CAN_connected == false){
		memset(j1939->CA, 0, 8);
		memset(j1939->errormessages_binary, 0, 12);
		j1939->SA_ACU = 0;
		CAN_connected = CANSPI_Initialize();
	}
}

// Special case for sending a request in J1939 of 3 bytes of PNG
static void write_CAN_PGN_request(uint8_t ID, uint8_t data[]){
	txMessage.frame.idType = dEXTENDED_CAN_MSG_ID_2_0B;
	txMessage.frame.id = ID;
	txMessage.frame.dlc = 3;
	txMessage.frame.data0 = data[0];
	txMessage.frame.data1 = data[1];
	txMessage.frame.data2 = data[2];
	CANSPI_Transmit(&txMessage);
}

void write_1939_request_for_claim_address(J1939* j1939){
	connect_can_bus(j1939);
	uint8_t data[3] = {0x0, 0xEE, 0x00};
	uint32_t ID = 0x18EAFFFE; // FE = 254 = No SA address known
	write_CAN_PGN_request(ID, data);
	HAL_Delay(100);
}
Användarvisningsbild
sodjan
EF Sponsor
Inlägg: 43149
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping
Kontakt:

Re: Transport protokoll i J1939-21 - Hur gör man för skicka 9 bytes?

Inlägg av sodjan »

> Idag utför jag inget Request Message eller ACK. Tror du jag måste göra detta?

Frågar du mig? :-) Inte en susning...
DanielM
Inlägg: 2166
Blev medlem: 5 september 2019, 14:19:58

Re: Transport protokoll i J1939-21 - Hur gör man för skicka 9 bytes?

Inlägg av DanielM »

Nu fungerar det att sätta adressen! :) Vad glad jag blir!
Jag kan berätta lite kort hur jag gjorde så kanske du kan förklara med lite CPU språk.

För att få meddelanden från ACU till ECU så börjar ECU först ansluta MCP2515.
Detta görs vid denna lilla fina C-kod där CAN_connected är statiska och CA är en 8 uint8_t array och SA_ACU är uint8_t variabel samt j1939 är en struktur.

Kod: Markera allt

// Connect can-bus, if we are not connected
static void connect_can_bus(J1939* j1939){
	if(CAN_connected == false){
		memset(j1939->CA, 0, 8);
		memset(j1939->errormessages_binary, 0, 12);
		j1939->SA_ACU = 0;
		CAN_connected = CANSPI_Initialize();
	}
}
Så fort jag får anslutning så skickar ACU sina CA NAME + SA_ACU adress.

Kod: Markera allt

// Read the 1939 message
void read_1939_message(J1939* j1939) {
	// Check if we have connected the CAN
	connect_can_bus(j1939);

	uint32_t ID;
	uint8_t data[8];
	if (read_CAN_message(&ID, data) && CAN_connected) {
		uint8_t id0 = ID >> 24;
		uint8_t id1 = ID >> 16;
		uint8_t id2 = ID >> 8;
		uint8_t id3 = ID;
		// Check what message we got
		if (id0 == 0x18 && id1 == 0xEE && id2 == 0xFF && id3 != 0xFE) {
			// Address claimed
			j1939->SA_ACU = id3;
			memcpy(j1939->CA, data, 8);
		} else if (id0 == 0x18 && id1 == 0xEE && id2 == 0xFF && id3 == 0xFE) {
			// Address not claimed
			j1939->SA_ACU = 0;
			j1939->errormessages_binary[0] = true;
			memcpy(j1939->CA, data, 8);
		} else if (id0 == 0x18 && id1 == 0xFE && id2 == 0xCA && id3 == j1939->SA_ACU) {
Vid denna koddel så ändrade jag från detta.

Kod: Markera allt

		if (id0 == 0x18 && id1 == 0xEE && id2 == 0xFF && id3 != 0xFE) {
			// Address claimed
			j1939->SA_ACU = id3;
			memcpy(j1939->CA, data, 8);
Till detta

Kod: Markera allt

		
		if (id0 == 0x18 && id1 == 0xEE && id2 == 0xFF && id3 != 0xFE) {
			// Address claimed
			j1939->SA_ACU = 0x80; // Min nya adress
			 memcpy(j1939->CA, data, 8);
			 write_1939_CA_names_and_source_address(j1939);

Då fungerar det! Alltså detta är alltså det absolut första som görs så fort vi har fått anslutning med MCP2515.

Slutsats:
Innan man skickar TP BAM så MÅSTE man vänta minst 750 ms. Så jag väntar 1000 ms och detta löse problemet! :D
DanielM
Inlägg: 2166
Blev medlem: 5 september 2019, 14:19:58

Re: Transport protokoll i J1939-21 - Hur gör man för skicka 9 bytes?

Inlägg av DanielM »

Någon som känner igen DM14, DM15 och DM16 i J1939?

Jag tänkte bara fråga vad pointer betyder?
Markering_077.png
Markering_078.png
Markering_079.png
Kan pointer betyda Address[DEC]?
Markering_080.png
Du har inte behörighet att öppna de filer som bifogats till detta inlägg.
Rick81
Inlägg: 746
Blev medlem: 30 december 2005, 13:07:09

Re: Transport protokoll i J1939-21 - Hur gör man för skicka 9 bytes?

Inlägg av Rick81 »

Pointer är väl bara minnesadressen du vill läsa ifrån?
DanielM
Inlägg: 2166
Blev medlem: 5 september 2019, 14:19:58

Re: Transport protokoll i J1939-21 - Hur gör man för skicka 9 bytes?

Inlägg av DanielM »

Okej! Nu har jag grottat i lite saker nu. Nu ska ni få höra!

DM14 är bara en förfrågan till minnet om man vill skriva eller läsa. Man kan välja Flash-minnet eller EEPROM eller variabel-minnet, vet ej vad variabelminnet betyder dock.
Här är en procedur hur man anropar minnet.
  • 1. Length betyder längden på datat du vill ändra eller läsa.
    2. Pointer Type säts antingen till 1 eller 0. Om det är 0 så får du ingen återkoppling om det är OK att läsa eller skriva. Sätter du den till 1 så får du ett så kallat DM15 meddelande som beskriver statusen
    3. Command är om du vill läsa eller skriva
    4. Pointer är själva adresssnummret till just den variabeln eller värdet du vill ändra.
    5. Pointer extension skall vara 1 om du vill läsa eller skriva från EEPROM
    6. Key/User level är som ett lås där man kan hindra andra användare från att läsa eller skriva till EEPROM. För att läsa så skriver vi key = 0xFFFF. För att skriva så väljer vi key = 0x2505
Efter man har skickat sitt DM14 så får man ett DM15.
Markering_082.png
Här behöver vi bara läsa utav status då det är just status som bestämmer om vi kan läsa eller inte.
Markering_083.png
Men då kommer jag till frågan. Låt oss säga att vi har fått grönt ljus av DM15 att läsa eller skriva. Hur ska jag då tolka DM16?
Markering_084.png
Jag har hittat ett dokument här http://www.unece.org/fileadmin/DAM/tran ... 40-06e.pdf
Som beskriver lite om DM16 men jag kan inte tolka vad "Number of occurrences" betyder.
Markering_085.png
Jag har lite C-kod som beskriver kontrollflödet. Men jag har ingen aning hur jag skall tolka DM16. Kommer det direkt från ACU till ECU efter jag har fått DM15?

Kod: Markera allt

// Send a memory request for access EEPROM and ask for a diagnostic message DM15
static void DM14_Memory_access_request(uint32_t ID, uint16_t length, uint8_t command, uint32_t pointer, uint16_t key){
	uint8_t data[8];
	data[0] = length; // Length LSB
	data[1] = (length >> 3) | (1 << 4) | (command << 1) | 1; // Length MSB, Pointer Type(Diagnostic message), Command, 1 (Always)
	data[2] = pointer; // Pointer LSB
	data[3] = pointer >> 8;
	data[4] = pointer >> 16; // Pointer MSB
	data[5] = 0x1; // Pointer extension 1 for access EEPROM
	data[6] = key; // Key LSB
	data[7] = key >> 8; // Key MSB
	write_CAN_message(ID, data);
}

// Request configuration parameters
void write_1939_configuration_request(J1939* j1939, uint8_t command){
	uint32_t ID = (0x18D9 << 16) | (j1939->SA_ACU << 8) | j1939->SA_ECU;
	HAL_Delay(1000);

	/*
	 * Pointers:
	 * 646 = Sensor_Stall_Neutral_Enable
	 * 647 = Sensor_Stall_Normal_Enable
	 *
	 * Length:
	 * 1 = Sensor_Stall_Neutral_Enable
	 * 1 = Sensor_Stall_Normal_Enable
	 */
	uint8_t length_eeprom_values[2] = {1, 1};
	uint8_t pointers_eeprom_address[2] = {646, 647};

	// DM14(Ask) -> DM15(Status) -> DM16(Read/Write) -> DM14(Close)
	for(uint8_t i = 0; i < 2; i++){
		// Send a DM14 request
		if(command == DM14_Read)
			DM14_Memory_access_request(ID, length_eeprom_values[i], DM14_Read, pointers_eeprom_address[i], 0xFFFF); // 0xFFFF = No key
		else if (command == DM14_Write)
			DM14_Memory_access_request(ID, length_eeprom_values[i], DM14_Write, pointers_eeprom_address[i], 0x2505); // 0xFFFF = Write key

		// Read until we got a DM15 message response
		j1939->DM15_Status = DM15_Reserved;
		while(j1939->DM15_Status == DM15_Reserved){
			read_1939_message(j1939); // Will update j1939->DM15_Status
		}

		// What does it say
		if(j1939->DM15_Status == DM15_Proceed){
			if(command == DM14_Read)
				readDM16();
			else if (command == DM14_Write)
				writeDM16();

			// Close the read operation of DM14
			DM14_Memory_access_request(ID, length_eeprom_values[i], DM14_Operation_Completed, pointers_eeprom_address[i], 0xFFFF);

		}else if(j1939->DM15_Status == DM15_Busy){
				return; // One single Busy status, then we cannot do anything yet
		}
	}
}
Du har inte behörighet att öppna de filer som bifogats till detta inlägg.
DanielM
Inlägg: 2166
Blev medlem: 5 september 2019, 14:19:58

Re: Transport protokoll i J1939-21 - Hur gör man för skicka 9 bytes?

Inlägg av DanielM »

Okej! Framsteg nu! :tumupp:

Jag börjar med att anropa DM14 (memory request) med denna typ av data. Se till höger där jag har en array uint8_t av 8 bytes.
Markering_086.png
Hittar vi på databladet så betyder det att jag väljer

Kod: Markera allt

byte1 = 0b00000001 (Längd på EEPROM värdet är 1 som vi vill ha tillåtelse till)
byte2 = 0b00010011 (Pointer Type = 1(Vi vill ha DM15 meddelande som respons), Command = 1 (Read). Sista 1:an är fixerad
byte3 = 0b10000110 (Sista bits för adressen 646)
byte4 = 0b00000010 (Första bits för adressen 646)
byte5 = 0b00000000 (Med tanke på att 646 är inte mer än 16-bit så blir denna noll)
byte6 = 0b00000001 (Pointer Extension = 1 betyder att läser eller skriver till EEPROM)
byte7 = 0b11111111 (Key LSB 0xFF = 255 = Vi vill läsa)
byte8 = 0b11111111 (Key MSB 0xFF = 255 = Vi vill läsa)
Men då kommer mitt DM15 svar.
Markering_087.png

Kod: Markera allt

byte1 = 0b00000000 ( Detta betyder att det finns inget EEPROM som vi har valt, som är tillåtet att läsa eller skriva. I detta fall läsa)
byte2 = 0b00000011 (Status = Busy = Upptagen)
byte3 -> byte8 = 0b1111111 ( Enligt databaldet är alla 0xFF på byte3 till byte8)
Så något gör så att jag kan ej läsa EEPROM.

Kod: Markera allt

// Send a memory request for access EEPROM and ask for a diagnostic message DM15
static void DM14_Memory_access_request(uint32_t ID, uint16_t length, uint8_t command, uint32_t pointer, uint16_t key){
	uint8_t data[8];
	data[0] = length; // Length LSB
	data[1] = (length >> 3) | (1 << 4) | (command << 1) | 1; // Length MSB, Pointer Type(Diagnostic message), Command, 1 (Always)
	data[2] = pointer; // Pointer LSB
	data[3] = pointer >> 8;
	data[4] = pointer >> 16; // Pointer MSB
	data[5] = 0x1; // Pointer extension 1 for access EEPROM
	data[6] = key; // Key LSB
	data[7] = key >> 8; // Key MSB
	write_CAN_message(ID, data);
}

// Request configuration parameters
void write_1939_configuration_request(J1939* j1939, uint8_t command){
	uint32_t ID = (0x18D9 << 16) | (j1939->SA_ACU << 8) | j1939->SA_ECU;
	HAL_Delay(1000);

	/*
	 * Pointers:
	 * 646 = Sensor_Stall_Neutral_Enable
	 * 647 = Sensor_Stall_Normal_Enable
	 *
	 * Length:
	 * 1 = Sensor_Stall_Neutral_Enable
	 * 1 = Sensor_Stall_Normal_Enable
	 */
	const uint8_t length_eeprom_values[2] = {1, 1}; // Between 1 and 7 only!
	const uint32_t pointers_eeprom_address[2] = {646, 647}; // Same indexing for j1939->EEPROM_values

	// DM14(Ask) -> DM15(Status) -> DM16(Read/Write) -> DM14(Close)
	for(uint8_t i = 0; i < 2; i++){
		// Send a DM14 request
		if(command == DM14_Read)
			DM14_Memory_access_request(ID, length_eeprom_values[i], DM14_Read, pointers_eeprom_address[i], 0xFFFF); // 0xFFFF = No key
		else if (command == DM14_Write)
			DM14_Memory_access_request(ID, length_eeprom_values[i], DM14_Write, pointers_eeprom_address[i], 0x2505); // 0x2505 = Write key

		// Read until we got a DM15 message response
		j1939->DM15_Status = DM15_Reserved;
		while(j1939->DM15_Status == DM15_Reserved){
			read_1939_message(j1939); // Will update j1939->DM15_Status
		}

		// What does it say
		if(j1939->DM15_Status == DM15_Proceed){
			if(command == DM14_Read){
				j1939->DM16_data[0] = 0;
				while(j1939->DM16_data[0] == 0){
					read_1939_message(j1939); // As long DM16_data[0], then we have not receive our DM16 data yet
				}
			}else if (command == DM14_Write){
				uint8_t data[8];
				memset(data, 0, 8);
				data[0] = length_eeprom_values[i]; // Between 1 and 7 only!
				for(uint8_t j = 1; j < data[0]; j++){
					data[j] = j1939->EEPROM_values[i] >> 8*(j-1); // EEPROM_values are uint16_t
				}
				write_CAN_message(ID, data);
			}
		}
		// Close the read operation of DM14
		DM14_Memory_access_request(ID, length_eeprom_values[i], DM14_Operation_Completed, pointers_eeprom_address[i], 0xFFFF);

		// Break the for-loop and return
		if(j1939->DM15_Status == DM15_Busy){
			break; // One single Busy status, then we cannot do anything yet
		}
	}
}
Du har inte behörighet att öppna de filer som bifogats till detta inlägg.
Rick81
Inlägg: 746
Blev medlem: 30 december 2005, 13:07:09

Re: Transport protokoll i J1939-21 - Hur gör man för skicka 9 bytes?

Inlägg av Rick81 »

Du är säker på att motorn har ett EEPROM?
Skriv svar