Hello,
I used 2 a) [ set FRAMESZ to 31 for 32bit frame size and control CS manually and fill data registers as per desired number of word transfer.] with some dummy data and it worked. Now, when I tried with my actual task where I need to communicate with LAN8650 chip, I should write/read by sending control header first where the respective address should be present:

For this purpose I used the below code :
#include "S32K144.h" /* include peripheral declarations S32K144 */
#define CS_LOW() (PTB->PCOR = (1 << 5)) // Clear bit to pull CS low
#define CS_HIGH() (PTB->PSOR = (1 << 5)) // Set bit to pull CS high
//System registers (MMS = 0)
const TC6Reg TC6ADR_RESET = { .mms = 0x00, .addr = 0x003 };
const TC6Reg TC6ADR_CONFIG0 = {.mms = 0x00, 0x0004};
const TC6Reg TC6ADR_STATUS0 = {.mms = 0x00, 0x0008};
const TC6Reg TC6ADR_IMASK0 = {.mms = 0x00, 0x000C};
const TC6Reg TC6ADR_PLCACTL0 = {.mms = 0x04, 0xCA01};
const TC6Reg TC6ADR_PLCACTL1 = {.mms = 0x04, 0xCA02};
const TC6Reg TC6ADR_PLCASTAT = {.mms = 0x04, 0xCA03};
const TC6Reg TC6ADR_MAC_NCR = {.mms = 0x01, 0x0000};
const TC6Reg TC6ADR_MAC_NCFGR = {.mms = 0x01, 0x0001};
uint32_t tx_16bits = 0xFD00FD00;
uint32_t tx_32bits_array[2] = {0xFD00, 0X1010};
uint32_t LPSPI0_16bits_read; /* Returned data in to SPI */
uint16_t lan8650_phy_id = 0;
uint32_t tx_upper = 0xFD00FD00;
uint32_t tx_lower = 0x1010ABCD;
uint32_t rx_upper, rx_lower;
// Calculates odd parity for a 32-bit word (excluding bit 0)
uint8_t calculate_parity(uint32_t word31to1) {
uint8_t count = 0;
int i;
for (i = 1; i < 32; i++) {
if ((word31to1 >> i) & 0x01) count++;
}
return (count % 2 == 0) ? 0 : 1; // Return 0 if even (to make odd)
}
uint32_t build_ctrl_header(uint8_t wnr, uint8_t mms, uint16_t addr, uint8_t num_regs) {
uint32_t header = 0;
header |= (0U << 31); // DNC = 0 (Control)
header |= (0U << 30); // HDRB = 0 (Ignored on write)
header |= ((wnr & 0x01) << 29); // WNR: 1 = write, 0 = read
header |= (0U << 28); // AID = 0 (auto-increment)
header |= ((mms & 0x0F) << 24); // MMS = memory map select
header |= ((addr & 0xFFFF) << 8); // Register address
header |= ((num_regs & 0x7F) << 1); // Length (in registers), shifted to [7:1]
uint8_t parity = calculate_parity(header & 0xFFFFFFFE); // Clear bit 0 for parity calc
header |= parity; // Set bit 1 to make parity odd
return header;
}
void LPSPI0_init_master(void) {
PCC->PCCn[PCC_LPSPI0_INDEX] = 0; /* Disable clocks to modify PCS ( default) */
PCC->PCCn[PCC_LPSPI0_INDEX] = 0xC6000000; /* Enable PCS=SPLL_DIV2 (40 MHz func'l clock) */
LPSPI0->CR = 0x00000000; /* Disable module for configuration */
LPSPI0->IER = 0x00000000; /* Interrupts not used */
LPSPI0->DER = 0x00000000; /* DMA not used */
LPSPI0->CFGR0 = 0x00000000; /* Defaults: */
/* RDM0=0: rec'd data to FIFO as normal */
/* CIRFIFO=0; Circular FIFO is disabled */
/* HRSEL, HRPOL, HREN=0: Host request disabled */
LPSPI0->CFGR1 = 0x00000001; /* Configurations: master mode*/
/* PCSCFG=0: PCS[3:2] are enabled */
/* OUTCFG=0: Output data retains last value when CS negated */
/* PINCFG=0: SIN is input, SOUT is output */
/* MATCFG=0: Match disabled */
/* PCSPOL=0: PCS is active low */
/* NOSTALL=0: Stall if Tx FIFO empty or Rx FIFO full */
/* AUTOPCS=0: does not apply for master mode */
/* SAMPLE=0: input data sampled on SCK edge */
/* MASTER=1: Master mode */
LPSPI0->TCR = 0x1100001F; /* Transmit cmd: PCS3, 16 bits, prescale func'l clk by 4, etc*/
/* CPOL=0: SCK inactive state is low */
/* CPHA=0: On the rising edge of SCLK the data is captured, while on the falling edge of SCLK the data will change
/* PRESCALE=2: Functional clock divided by 2**2 = 4 */
/* PCS=3: Transfer using PCS3 */
/* LSBF=0: Data is transfered MSB first */
/* BYSW=0: Byte swap disabled */
/* CONT, CONTC=0: Continuous transfer disabled */
/* RXMSK=0: Normal transfer: rx data stored in rx FIFO */
/* TXMSK=0: Normal transfer: data loaded from tx FIFO */
/* WIDTH=0: Single bit transfer */
/* FRAMESZ=31: # bits in frame = 31+1=32 */
LPSPI0->CCR = 0x04090808; /* Clock dividers based on prescaled func'l clk of 100 nsec */
/* SCKPCS=4: SCK to PCS delay = 4+1 = 5 (500 nsec) */
/* PCSSCK=4: PCS to SCK delay = 9+1 = 10 (1 usec) */
/* DBT=8: Delay between Transfers = 8+2 = 10 (1 usec) */
/* SCKDIV=8: SCK divider =8+2 = 10 (1 usec: 1 MHz baud rate) */
LPSPI0->FCR = 0x00000003; /* RXWATER=0: Rx flags set when Rx FIFO >0 */
/* TXWATER=3: Tx flags set when Tx FIFO <= 3 */
LPSPI0->CR = 0x00000009; /* Enable module for operation */
/* DBGEN=1: module enabled in debug mode */
/* DOZEN=0: module enabled in Doze mode */
/* RST=0: Master logic not reset */
/* MEN=1: Module is enabled */
}
void LPSPI0_tx_32bits (uint32_t send) {
while((LPSPI0->SR & LPSPI_SR_TDF_MASK)>>LPSPI_SR_TDF_SHIFT==0);
/* Wait for Tx FIFO available */
LPSPI0->TDR = send; /* Transmit data */
LPSPI0->SR |= LPSPI_SR_TDF_MASK; /* Clear TDF flag */
}
uint32_t LPSPI0_rx_32bits (void) {
uint32_t recieve = 0;
while((LPSPI0->SR & LPSPI_SR_RDF_MASK)>>LPSPI_SR_RDF_SHIFT==0);
/* Wait at least one RxFIFO entry */
recieve= LPSPI0->RDR; /* Read received data */
LPSPI0->SR |= LPSPI_SR_RDF_MASK; /* Clear RDF flag */
return recieve; /* Return received data */
}
void SOSC_init_8MHz(void) {
SCG->SOSCDIV=0x00000101; /* SOSCDIV1 & SOSCDIV2 =1: divide by 1 */
SCG->SOSCCFG=0x00000024; /* Range=2: Medium freq (SOSC between 1MHz-8MHz)*/
/* HGO=0: Config xtal osc for low power */
/* EREFS=1: Input is external XTAL */
while(SCG->SOSCCSR & SCG_SOSCCSR_LK_MASK); /* Ensure SOSCCSR unlocked */
SCG->SOSCCSR=0x00000001; /* LK=0: SOSCCSR can be written */
/* SOSCCMRE=0: OSC CLK monitor IRQ if enabled */
/* SOSCCM=0: OSC CLK monitor disabled */
/* SOSCERCLKEN=0: Sys OSC 3V ERCLK output clk disabled */
/* SOSCLPEN=0: Sys OSC disabled in VLP modes */
/* SOSCSTEN=0: Sys OSC disabled in Stop modes */
/* SOSCEN=1: Enable oscillator */
while(!(SCG->SOSCCSR & SCG_SOSCCSR_SOSCVLD_MASK)); /* Wait for sys OSC clk valid */
}
void SPLL_init_160MHz(void) {
while(SCG->SPLLCSR & SCG_SPLLCSR_LK_MASK); /* Ensure SPLLCSR unlocked */
SCG->SPLLCSR = 0x00000000; /* SPLLEN=0: SPLL is disabled (default) */
SCG->SPLLDIV = 0x00000302; /* SPLLDIV1 divide by 2; SPLLDIV2 divide by 4 */
SCG->SPLLCFG = 0x00180000; /* PREDIV=0: Divide SOSC_CLK by 0+1=1 */
/* MULT=24: Multiply sys pll by 4+24=40 */
/* SPLL_CLK = 8MHz / 1 * 40 / 2 = 160 MHz */
while(SCG->SPLLCSR & SCG_SPLLCSR_LK_MASK); /* Ensure SPLLCSR unlocked */
SCG->SPLLCSR = 0x00000001; /* LK=0: SPLLCSR can be written */
/* SPLLCMRE=0: SPLL CLK monitor IRQ if enabled */
/* SPLLCM=0: SPLL CLK monitor disabled */
/* SPLLSTEN=0: SPLL disabled in Stop modes */
/* SPLLEN=1: Enable SPLL */
while(!(SCG->SPLLCSR & SCG_SPLLCSR_SPLLVLD_MASK)); /* Wait for SPLL valid */
}
void NormalRUNmode_80MHz (void) { /* Change to normal RUN mode with 8MHz SOSC, 80 MHz PLL*/
SCG->RCCR=SCG_RCCR_SCS(6) /* PLL as clock source*/
|SCG_RCCR_DIVCORE(0b01) /* DIVCORE=1, div. by 2: Core clock = 160/2 MHz = 80 MHz*/
|SCG_RCCR_DIVBUS(0b01) /* DIVBUS=1, div. by 2: bus clock = 40 MHz*/
|SCG_RCCR_DIVSLOW(0b10); /* DIVSLOW=2, div. by 3: SCG slow, flash clock= 26 2/3 MHz*/
while (((SCG->CSR & SCG_CSR_SCS_MASK) >> SCG_CSR_SCS_SHIFT ) != 6) {}
/* Wait for sys clk src=SPLL */
}
/* TXWATER=3: Tx flags set when Tx FIFO <= 3 */
void WDOG_disable (void){
WDOG->CNT=0xD928C520; /*Unlock watchdog*/
WDOG->TOVAL=0x0000FFFF; /*Maximum timeout value*/
WDOG->CS = 0x00002100; /*Disable watchdog*/
}
void PORT_init (void) {
//Master:
PCC->PCCn[PCC_PORTB_INDEX] |= PCC_PCCn_CGC_MASK;
PORTB->PCR[2] |= PORT_PCR_MUX(3); /*Port B2: MUX = ALT3, SCK*/
PORTB->PCR[3] |= PORT_PCR_MUX(3); /*Port B3: MUX = ALT3, SIN*/
PORTB->PCR[4] |= PORT_PCR_MUX(3); /*Port B4: MUX = ALT3, SOUT*/
//PORTB->PCR[5] |= PORT_PCR_MUX(3);
PORTB->PCR[5] |= PORT_PCR_MUX(1);
PTB->PDDR |= (1<<5);
PTB->PSOR |= (1<<5);
}
void lan8650_write_reset(void) {
uint32_t header = build_ctrl_header(1, 0x00, 0x0003, 0); // Write to RESET reg
CS_LOW();
LPSPI0_tx_32bits(header); (void)LPSPI0_rx_32bits(); // Write header
LPSPI0_tx_32bits(0x00000001); (void)LPSPI0_rx_32bits(); // Write data
CS_HIGH();
}
void lan8650_write_imask0(uint32_t value) {
uint32_t header = build_ctrl_header(1, 0x00, 0x000C, 0);
CS_LOW();
LPSPI0_tx_32bits(header); (void)LPSPI0_rx_32bits();
LPSPI0_tx_32bits(value); (void)LPSPI0_rx_32bits();
CS_HIGH();
}
uint32_t lan8650_read_imask0(void) {
uint32_t header = build_ctrl_header(0, 0x00, 0x000C, 0);
uint32_t data = 0;
CS_LOW();
LPSPI0_tx_32bits(header); (void)LPSPI0_rx_32bits(); // Send header
LPSPI0_tx_32bits(0x00000000); // Dummy to clock data
data = LPSPI0_rx_32bits(); // Get data
CS_HIGH();
return data;
}
int main(void) {
uint32_t imask_read_value;
volatile int i;
// Usual system and SPI setup
WDOG_disable();
SOSC_init_8MHz();
SPLL_init_160MHz();
NormalRUNmode_80MHz();
PORT_init(); // Configure SPI pins
LPSPI0_init_master(); // Init LPSPI master
// Small delay before starting (optional)
for ( i = 0; i < 100000; i++); // Optional delay
// Write RESET
lan8650_write_reset();
// Optional delay to allow reset to complete
for ( i = 0; i < 100000; i++);
// Unmask all interrupts
lan8650_write_imask0(0x00000000);
// Read IMASK0 to verify
imask_read_value = lan8650_read_imask0();
// Set breakpoint here to inspect imask_read_value
while (1) { }
return 0;
}
Here, I am trying to Write 0x00000000 to IMASK0 register address and trying to readback the same address in order to ensure the value has been written properly. But I got value has 0xC0000001 instead of 0xC0000000. (IMASK0 has 31 to 16 bits as reserved and Read-Only bits thus 0xC000 can be fixed even i try to write it as 0, thus we can neglect that) But the lower 16 bits are R/W and thus it should be 0.


For debugging purpose, in the above code I set breakpoint in the last while loop and it successfully hits (above picture) thus seems like write and read happening proper (not 100% sure, my assumption) but the value read is wrong.
I tried all possibilities and still couldn't find where it went wrong. Kindly guide me to solve this issue.
Thanks in advance.