







/*
* ExternalMemory.c
*
* Created on: Dec 13, 2025
* Author: Ajay Gupta
*/
#include "ExternalMemory.h"
#include "Siul2_Port_Ip.h"
#include "Siul2_Dio_Ip.h"
#include "Cache_Ip.h"
#include "Lpspi_Ip.h"
#include "CDD_Rm.h"
#include "Dma_Ip.h"
#include <string.h>
volatile bool g_spiTransferComplete = false;
volatile uint32_t g_W25Q_ID = 0;
#ifdef USE_NON_CHACHABLE_REGION
/* Allocated in non-cacheable RAM: No manual cache cleaning needed */
#pragma GCC section bss ".mcal_bss_no_cacheable"
__attribute__(( aligned(32) )) uint8_t RxBuffer[BCC_MSG_SIZE];
#pragma GCC section bss
#pragma GCC section data ".mcal_data_no_cacheable"
__attribute__(( aligned(32) )) uint8_t TxBuffer[BCC_MSG_SIZE] = {0};
#pragma GCC section data
#else
/* Allocated in cacheable RAM: Requires Cache_Ip_Clean/Invalidate */
__attribute__(( aligned(32) )) uint8_t RxBuffer[BCC_MSG_SIZE];
__attribute__(( aligned(32) )) uint8_t TxBuffer[BCC_MSG_SIZE];
#endif
/*
* winbond W25Q16JV - 16 megabits in size.
W25Q16 pins Spi pins in Mcu
Cs pin connected to Fcs(SPI2)
Data out connected to Miso(SPI2)
Data in connected to Mosi(SPI2)
Clock connected to clock(SPI2)
Standard(single)SPI has 4 pins: Clk, CS, Din, Dout.
this 16 megabits variant has the memory distributed among the 8192 programmable pages, each page being 256 bytes in size.
We can program 256 bytes at once.
we can't erase a single page but we can erase a grp of 16 pages which is called a sector and is 4kb in size that can be erased.
we can also erase a block which is a group of 128 pages(32Kb)or 256 pages(64Kb)
block diagram of memory:
for ex: we have 1 block which has 16 sectors, each sector is 4 kb in size and contains 16 pages. 1 block =16sector x 16 pages =256 pages.
in w25q16jv we have 32 blocks in total 256 pages for 1 block x 32 block=8192 pages.
*/
void lpspi_callback_dma(uint8 Instance, Lpspi_Ip_EventType Event)
{
if(Event == LPSPI_IP_EVENT_END_TRANSFER)
{
/* If cacheable, Invalidate ensures we fetch the fresh DMA data from main memory */
#ifndef USE_NON_CHACHABLE_REGION
Cache_Ip_InvalidateByAddr(CACHE_IP_CORE, CACHE_IP_DATA, (uint32)&RxBuffer[0U], BCC_MSG_SIZE);
#endif
g_spiTransferComplete = true;
}
else if (Event == LPSPI_IP_EVENT_FAULT)
{
g_spiTransferComplete = true;
}
}
/*
* Function Name: W25Q_Reset
* Description: Before starting a new session with the chip we should reset it.
* This would terminate any on going operation and the device will return to its default power-on state.
* It will lose all the current volatile settings, such as Volatile Status Register bits, Write Enable Latch (WEL) status, Program/Erase Suspend status, Read parameter setting (P7-P0) and Wrap Bit setting (W6-W4).
* To avoid the accidental Reset, a Reset command is made of 2 instructions. these Instructions, “Enable Reset (66h)” and “Reset (99h)” must be issues in a sequence. Once the Reset command is accepted by the device, the device will take approximately 30us to reset. During this period, no command will be accepted.
*/
Lpspi_Ip_StatusType W25Q_Reset(void)
{
Lpspi_Ip_StatusType status;
/* Enable Reset (0x66) */
memset(TxBuffer, 0, BCC_MSG_SIZE);
TxBuffer[0] = 0x66;
g_spiTransferComplete = false;
#ifndef USE_NON_CHACHABLE_REGION
Cache_Ip_CleanByAddr(CACHE_IP_CORE, CACHE_IP_DATA, TRUE, (uint32)&TxBuffer[0U], 1);
#endif
status = Lpspi_Ip_AsyncTransmit(&MASTER_EXTERNAL_DEVICE, TxBuffer, NULL, 1, lpspi_callback_dma);
if (status != LPSPI_IP_STATUS_SUCCESS) return status;
while(g_spiTransferComplete == false);
/* Reset (0x99) */
TxBuffer[0] = 0x99;
g_spiTransferComplete = false;
#ifndef USE_NON_CHACHABLE_REGION
Cache_Ip_CleanByAddr(CACHE_IP_CORE, CACHE_IP_DATA, TRUE, (uint32)&TxBuffer[0U], 1);
#endif
status = Lpspi_Ip_AsyncTransmit(&MASTER_EXTERNAL_DEVICE, TxBuffer, NULL, 1, lpspi_callback_dma);
if (status != LPSPI_IP_STATUS_SUCCESS) return status;
while(g_spiTransferComplete == false);
for (volatile uint32 i = 0; i < 5000; i++);
return LPSPI_IP_STATUS_SUCCESS;
}
Lpspi_Ip_StatusType W25Q_ReadID(void)
{
Lpspi_Ip_StatusType status;
memset(TxBuffer, 0, BCC_MSG_SIZE);
memset(RxBuffer, 0, BCC_MSG_SIZE);
TxBuffer[0] = 0x9F;
g_spiTransferComplete = false;
#ifndef USE_NON_CHACHABLE_REGION
Cache_Ip_CleanByAddr(CACHE_IP_CORE, CACHE_IP_DATA, TRUE, (uint32)&TxBuffer[0U], 4);
#endif
/* Send 1 cmd byte and receive 3 ID bytes */
status = Lpspi_Ip_AsyncTransmit(&MASTER_EXTERNAL_DEVICE, TxBuffer, RxBuffer, 4, lpspi_callback_dma);
if (status != LPSPI_IP_STATUS_SUCCESS) return status;
while(g_spiTransferComplete == false);
g_W25Q_ID = ((uint32_t)RxBuffer[1] << 16) | ((uint32_t)RxBuffer[2] << | (uint32_t)RxBuffer[3];
return LPSPI_IP_STATUS_SUCCESS;
}
/*
* ExternalMemory.h
*
* Created on: Dec 13, 2025
* Author: Ajay Gupta
*/
#ifndef EXTERNALMEMORY_EXTERNALMEMORY_H_
#define EXTERNALMEMORY_EXTERNALMEMORY_H_
#include <stdint.h>
#include <stdbool.h>
#include "Cache_Ip.h"
#include "Lpspi_Ip.h"
#include "CDD_Rm.h"
#include "Dma_Ip.h"
#define USE_NON_CHACHABLE_REGION 1
#define No_of_Blocks 32
#define BCC_MSG_SIZE 12U
#define MASTER_EXTERNAL_DEVICE Lpspi_Ip_DeviceAttributes_SpiExternalDevice_0_Instance_2
extern Lpspi_Ip_StatusType lpspi_status;
extern Lpspi_Ip_HwStatusType lpspi_hw_status;
extern volatile bool g_spiTransferComplete;
void lpspi_callback_dma(uint8 Instance, Lpspi_Ip_EventType Event);
Lpspi_Ip_StatusType W25Q_Reset (void);
Lpspi_Ip_StatusType W25Q_ReadID (void);
#endif /* EXTERNALMEMORY_EXTERNALMEMORY_H_ */
void SPI_DMA_Init(void)
{
/* Initialize Dma */
Dma_Ip_Init(&Dma_Ip_xDmaInitPB);
/* Initialize Rm driver for using DmaMux*/
Rm_Init(&Rm_Config);
IntCtrl_Ip_EnableIrq(DMATCD0_IRQn);
IntCtrl_Ip_EnableIrq(DMATCD1_IRQn);
/* Initialise the LPSPI module*/
lpspi_status = Lpspi_Ip_Init(&Lpspi_Ip_PhyUnitConfig_SpiPhyUnit_1_Instance_2);
Lpspi_Ip_UpdateTransferMode(MASTER_EXTERNAL_DEVICE.Instance, LPSPI_IP_INTERRUPT);
}
clock and pin initialization also i have done can anyone check whether this configuration is correct