Member 13142768 Ответов: 1

Запись файла в память qspi


Привет,

У меня есть файл .bin, и я хочу записать его в память qspi.

[edit]добавлен блок кода - OriginalGriff[/edit]

Что я уже пробовал:

Я сбрасываю файл во время отладки программы. но я не могу правильно записать файл в буфер. Здесь я пишу код..

#include "xparameters.h"	/* SDK generated parameters */
#include "xqspips.h"		/* QSPI device driver */
#include "xil_printf.h"

#define QSPI_DEVICE_ID		XPAR_XQSPIPS_0_DEVICE_ID


#define WRITE_STATUS_CMD	0x01
#define WRITE_CMD		0x02
#define READ_CMD		0x03
#define WRITE_DISABLE_CMD	0x04
#define READ_STATUS_CMD		0x05
#define WRITE_ENABLE_CMD	0x06
#define FAST_READ_CMD		0x0B
#define DUAL_READ_CMD		0x3B
#define QUAD_READ_CMD		0x6B
#define BULK_ERASE_CMD		0xC7
#define	SEC_ERASE_CMD		0xD8
#define READ_ID			0x9F


#define COMMAND_OFFSET		0 /* FLASH instruction */
#define ADDRESS_1_OFFSET	1 /* MSB byte of address to read or write */
#define ADDRESS_2_OFFSET	2 /* Middle byte of address to read or write */
#define ADDRESS_3_OFFSET	3 /* LSB byte of address to read or write */
#define DATA_OFFSET		4 /* Start of Data for Read/Write */
#define DUMMY_OFFSET		4 /* Dummy byte offset for fast, dual and quad
				     reads */
#define DUMMY_SIZE		1 /* Number of dummy bytes for fast, dual and
				     quad reads */
#define RD_ID_SIZE		4 /* Read ID command + 3 bytes ID response */
#define BULK_ERASE_SIZE		1 /* Bulk Erase command size */
#define SEC_ERASE_SIZE		4 /* Sector Erase command + Sector address */

#define OVERHEAD_SIZE		4

/*
 * The following constants specify the page size, sector size, and number of
 * pages and sectors for the FLASH.  The page size specifies a max number of
 * bytes that can be written to the FLASH with a single transfer.
 */
#define SECTOR_SIZE		0x10000
#define NUM_SECTORS		0x100
#define NUM_PAGES		0x10000
#define PAGE_SIZE		256

/*
 * Number of flash pages to be written.
 */
#define PAGE_COUNT		1611

/*
 * Flash address to which data is ot be written.
 */
#define TEST_ADDRESS		0x00000000
#define UNIQUE_VALUE		0x05
/*
 * The following constants specify the max amount of data and the size of the
 * the buffer required to hold the data and overhead to transfer the data to
 * and from the FLASH.
 */
#define MAX_DATA		PAGE_COUNT * PAGE_SIZE

/**************************** Type Definitions *******************************/

/***************** Macros (Inline Functions) Definitions *********************/

/************************** Function Prototypes ******************************/

void FlashErase(XQspiPs *QspiPtr, u32 Address, u32 ByteCount);

void FlashWrite(XQspiPs *QspiPtr, u32 Address, u32 ByteCount, u8 Command);

void FlashRead(XQspiPs *QspiPtr, u32 Address, u32 ByteCount, u8 Command);

int FlashReadID(void);

int QspiFlashPolledExample(XQspiPs *QspiInstancePtr, u16 QspiDeviceId);

/************************** Variable Definitions *****************************/

/*
 * The instances to support the device drivers are global such that they
 * are initialized to zero each time the program runs. They could be local
 * but should at least be static so they are zeroed.
 */
static XQspiPs QspiInstance;

/*
 * The following variable allows a test value to be added to the values that
 * are written to the FLASH such that unique values can be generated to
 * guarantee the writes to the FLASH were successful
 */
int Test = 5;

/*
 * The following variables are used to read and write to the flash and they
 * are global to avoid having large buffers on the stack
 */
u8 ReadBuffer[MAX_DATA + DATA_OFFSET + DUMMY_SIZE];
u8 WriteBuffer[PAGE_SIZE + DATA_OFFSET];

/*****************************************************************************/
/**
*
* Main function to call the QSPI Flash example.
*
* @param	None
*
* @return	XST_SUCCESS if successful, otherwise XST_FAILURE.
*
* @note		None
*
******************************************************************************/
int main(void)
{
	int Status;

	xil_printf("QSPI FLASH Polled Example Test \r\n");

	/*
	 * Run the Qspi Interrupt example.
	 */
	Status = QspiFlashPolledExample(&QspiInstance, QSPI_DEVICE_ID);
	if (Status != XST_SUCCESS) {
		xil_printf("QSPI FLASH Polled Example Test Failed\r\n");
		return XST_FAILURE;
	}

	xil_printf("Successfully ran QSPI FLASH Polled Example Test\r\n");
	return XST_SUCCESS;
}

/*****************************************************************************
*
* The purpose of this function is to illustrate how to use the XQspiPs
* device driver in polled mode. This function writes and reads data
* from a serial FLASH.
*
* @param	None.
*
* @return	XST_SUCCESS if successful, else XST_FAILURE.
*
* @note		None.
*
*****************************************************************************/
int QspiFlashPolledExample(XQspiPs *QspiInstancePtr, u16 QspiDeviceId)
{
	int Status;
	u8 *BufferPtr;
	u8 UniqueValue;
	int Count;
	int Page;
	XQspiPs_Config *QspiConfig;

	/*
	 * Initialize the QSPI driver so that it's ready to use
	 */
	QspiConfig = XQspiPs_LookupConfig(QspiDeviceId);
	if (NULL == QspiConfig) {
		return XST_FAILURE;
	}

	Status = XQspiPs_CfgInitialize(QspiInstancePtr, QspiConfig,
					QspiConfig->BaseAddress);
	if (Status != XST_SUCCESS) {
		return XST_FAILURE;
	}

	/*
	 * Perform a self-test to check hardware build
	 */
	Status = XQspiPs_SelfTest(QspiInstancePtr);
	if (Status != XST_SUCCESS) {
		return XST_FAILURE;
	}

	/*
	 * Initialize the write buffer for a pattern to write to the FLASH
	 * and the read buffer to zero so it can be verified after the read,
	 * the test value that is added to the unique value allows the value
	 * to be changed in a debug environment to guarantee
	 */
	for (UniqueValue = UNIQUE_VALUE, Count = 0; Count < PAGE_SIZE;
	     Count++, UniqueValue++) {
		WriteBuffer[DATA_OFFSET + Count] = (u8)(UniqueValue + Test);
	}
	memset(ReadBuffer, 0x00, sizeof(ReadBuffer));

	/*
	 * Set Manual Start and Manual Chip select options and drive HOLD_B
	 * pin high.
	 */
	XQspiPs_SetOptions(QspiInstancePtr, XQSPIPS_MANUAL_START_OPTION |
			XQSPIPS_FORCE_SSELECT_OPTION |
			XQSPIPS_HOLD_B_DRIVE_OPTION);

	/*
	 * Set the prescaler for QSPI clock
	 */
	XQspiPs_SetClkPrescaler(QspiInstancePtr, XQSPIPS_CLK_PRESCALE_8);

	/*
	 * Assert the FLASH chip select.
	 */
	XQspiPs_SetSlaveSelect(QspiInstancePtr);


	//FlashReadID();

	/*
	 * Erase the flash.
	 */
	//FlashErase(QspiInstancePtr, TEST_ADDRESS, MAX_DATA);

	/*
	 * Write the data in the write buffer to the serial FLASH a page at a
	 * time, starting from TEST_ADDRESS
	 */
	for (Page = 0; Page < PAGE_COUNT; Page++) {
		FlashWrite(QspiInstancePtr, (Page * PAGE_SIZE) + TEST_ADDRESS,
			   PAGE_SIZE, WRITE_CMD);
	}


	return XST_SUCCESS;
}

CPallini

- но я не могу правильно записать файл в буфер."
Это довольно расплывчато. Не могли бы вы дать нам больше информации?
Какое устройство вы программируете? Что такое QUAD SPI FLASH peripheral?

1 Ответов

Рейтинг:
12

Jochen Arndt

Вы нигде не пытаетесь записать данные. Похоже, что опубликованный код основан на коде из xqspips_flash_polled_example.с[^].

Если это так, то вы должны скопировать данные, которые будут записаны в &WriteBuffer[DATA_OFFSET] и позвонить FlashWrite() страница мудрая.

Непроверенный пример:

// pSrcData: Data read from file
// nSrcLen:  Number of bytes
// Assuming driver has been initialised

u32 nPage;
u32 nPages = nSrcLen / PAGE_SIZE;
u32 nLast = nSrcLen % PAGE_SIZE;
u32 nSpiAddress = 0; // Flash start address
u32 nOffset = 0;

#if 0
// Optional read and store last page here if data should be preserved
// Only necessary if nLast is not zero
u8 pPreserved[PAGE_SIZE]; 
if (nLast)
{
    FlashRead(QspiInstancePtr, nSpiAddress + nPages * PAGE_SIZE, PAGE_SIZE, READ_CMD);
    memcpy(pPreserved, &ReadBuffer[DATA_OFFSET], PAGE_SIZE);
}
#endif

// Erase flash pages to be written
u32 nMaxData = nPages * PAGE_SIZE;
if (nLast)
    nMaxData += PAGE_SIZE;
FlashErase(QspiInstancePtr, nSpiAddress, nMaxData);

for (nPage = 0; nPage < nPages; nPage++, nOffset += PAGE_SIZE) 
{
    memcpy(&WriteBuffer[DATA_OFFSET], pSrcData + nOffset, PAGE_SIZE);
    FlashWrite(QspiInstancePtr, nSpiAddress + nOffset, PAGE_SIZE, WRITE_CMD);
}
if (nLast)
{
    // Clear unused memory
    memset(&WriteBuffer[DATA_OFFSET + nLast], 0, PAGE_SIZE - nLast);
    // If the memory must be preserved, it must be read and stored before erasing
    //  and copied back here
    //memcpy(&WriteBuffer[DATA_OFFSET], pPreserved, PAGE_SIZE);
    memcpy(&WriteBuffer[DATA_OFFSET], pSrcData + nOffset, nLast);
    FlashWrite(QspiInstancePtr, nSpiAddress + nOffset, PAGE_SIZE, WRITE_CMD);
}

// Perform verification in a similar manner by reading data and comapre with pSrcData


CPallini

Мой 5.

Member 13142768

Привет,
Спасибо за ваш ответ. Я восстанавливаю файл перед выполнением flashwrite(), используя адрес буфера записи, я также попытался изменить количество байтов на MAX_DATA. Но это не работает....

Jochen Arndt

Похоже, вы до сих пор не поняли, как пишется флэш-память.

- Вы должны стереть память, прежде чем писать
- Вы не можете записать больше байтов размера страницы сразу во флэш-память
- Если у вас есть больше данных, вы должны писать страницу за страницей
- Поскольку ваша функция FlashWrite() использует определенный буфер (WriteBuffer), вы должны скопировать данные для записи в этот буфер перед вызовом функции
- Вы должны передать соответствующие аргументы (адрес флэш-памяти)

Я не могу протестировать код, потому что у меня нет оборудования. Но мой пример кода показывает, как это должно быть сделано.

В петле:

memcpy(&WriteBuffer[DATA_OFFSET], pSrcData + nOffset, PAGE_SIZE);

Копирует блок данных из pSrcData в буфер (pSrcData должен содержать полный файл).
FlashWrite(QspiInstancePtr, nSpiAddress + nOffset, PAGE_SIZE, WRITE_CMD);

Записывает блок данных (размер страницы) из буфера во флэш-память.

Member 13142768

Привет,
Извините, что спрашиваю об этом снова и снова. да, я понял, что мы не можем писать больше 1 страницы(256 байт) за один раз, поэтому мы используем цикл for в коде.

//for (Page = 0; Page < PAGE_COUNT; Page++)
{
FlashWrite(QspiInstancePtr, (Page * PAGE_SIZE) + TEST_ADDRESS,PAGE_SIZE, WRITE_CMD);
}
//
и вы дали файл pSrcData, который мы полностью восстанавливаем во время отладки.
И если вы хотите ,чтобы аппаратное обеспечение тестировало код, то вы можете выйти в интернет(teamviewer) и проверить аппаратное обеспечение....

Спасибо...

Jochen Arndt

Извините, но я не собираюсь проверять это для вас. Мы все здесь волонтеры, и у нас есть "основная" работа, чтобы зарабатывать деньги.

Почему вы удалили строку memcpy ()?
Без этого ничего не получится!

Member 13142768

Извините сэр,
Я посвежел и застрял в этом коде с 10 дней.... Большое спасибо за ваши ответы, вы действительно отлично справляетесь....
Если я объявлю здесь pSrcData, то я не смогу восстановить его во время отладки программы. и здесь я не могу объявить файл, который я хочу написать...
Пожалуйста, вы можете сказать мне, как объявить эту часть...

Jochen Arndt

pSrcData должен быть буфером, содержащим содержимое файла.

Чтение файла в выделенный буфер является базовым знанием языка Си:
- Получить размер файла
- Выделите буфер
- Откройте файл
- Считывание содержимого файла в буфер
- Закройте файл
- Используйте буфер
- Освободите буфер

struct stat st;
stat(filename, &st);
nSrcLen = st.st_size;
char *pSrcData = malloc(nSrclen);
FILE *f = fopen(filename, "rb");
fread(pSrcData, 1, nSrcLen, f);
fclose(f);
// Write to flash here
free(pSrcData);

Member 13142768

Привет,

то, что все члены структуры здесь, пожалуйста, опишите мне.

Jochen Arndt

Какая структура?

В любом случае: прочтите документацию и/или взгляните на определение структуры.

Для стат:
http://pubs.opengroup.org/onlinepubs/009695399/functions/stat.html
http://pubs.opengroup.org/onlinepubs/009695399/basedefs/sys/stat.h.html

Member 13142768

Привет,

Спасибо за вашу помощь.
Я попробовал следующий код, который вы дали, но я получаю ошибку как неопределенную ссылку на '_stat'


char *filename="qqspi.txt";
FILE *filesource=fopen(имя файла,"r");

/*используйте stat.st_size, если у вас есть библиотека <sys stat.h="">*/
ст стат структуру ;
stat(имя файла, &st);

долго filesize_stat= ст.st_size;

fseek(filesource,0,SEEK_END);
long filesize_ftell = ftell(filesource);
fseek(filesource,0,SEEK_SET);

char *pchar_filesource = malloc(filesize_stat);



fread(pchar_filesource, 1, filesize_stat, filesource);
fclose(файловый источник);

for (Page = 0; Page < PAGE_COUNT; Page++)
{
memcpy(&WriteBuffer[DATA_OFFSET], pchar_filesource + nOffset, PAGE_SIZE);
FlashWrite(QspiInstancePtr, TEST_ADDRESS + nOffset, PAGE_SIZE, WRITE_CMD);
}

бесплатно(pchar_filesource);

Jochen Arndt

Как я тебе и говорил:
Прочтите документацию по каждой используемой функции. Он содержит примеры и информацию о заголовочных файлах, которые должны быть включены.

Так что тебе придется

#include <sys/types.h>
#include <sys/stat.h>

или используйте другой метод, чтобы получить размер файла, например поиск.

Member 13142768

Я добавил оба заголовка, но результат все тот же, я заканчиваю с той же ошибкой.
как вы уже сказали, я пытался получить размер файла с помощью поиска... Я написал код ниже....

Чтобы скопировать в память из буфера, какое утверждение я должен дать?


char *filename="qqspi.txt";
char *source = NULL;
FILE *fptr = fopen(имя файла, "r");
if (fptr != NULL)
{
/* Перейдите в конец файла. */
if (fseek(fptr, 0L, SEEK_END) == 0)
{
/* Получить размер файла. */
long bufsize = ftell(fptr);
if (bufsize == -1)
{
xil_printf("QSPI флеш опрошенных пример получения размера файла произошла ошибка\р\н");
вернуться XST_FAILURE;
}

/* Выделите наш буфер до этого размера. */
source = malloc(sizeof(char) * (bufsize + 1));

/* Вернитесь к началу файла. */
if (fseek(fptr, 0L, SEEK_SET) != 0)
{
xil_printf("QSPI флеш опрошенных пример вернуться к началу файла произошла ошибка\р\н");
вернуться XST_FAILURE;
}

/* Считайте весь файл в память. */
size_t newLen = fread(source, sizeof(char), bufsize, fptr);
if (newLen == 0)
{
fputs("Ошибка чтения файла", stderr);
}
еще
{
source[++newLen] = '\0'; /* на всякий случай. */
}
}
fclose(fptr);
}

for (Page = 0; Page < PAGE_COUNT; Page++)
{
memcpy(&WriteBuffer[DATA_OFFSET], pchar_filesource + nOffset, PAGE_SIZE);
FlashWrite(QspiInstancePtr, TEST_ADDRESS + nOffset, PAGE_SIZE, WRITE_CMD);
}

бесплатный источник);

Jochen Arndt

"Чтобы скопировать в память из буфера, какое заявление я должен дать?"
Обычно memcpy (), но это зависит от того, что вы хотите сделать.

Подумайте о том, что вы хотите сделать, и перечитайте мой ответ:
Он вычисляет количество страниц из размера файла, но вы используете PAGE_COUNT.

Member 13142768

Я использую page_count, потому что max_data, который я могу написать, это
MAX_DATA[Page_size*Page_count]

т. е. определить MAX_DATA PAGE_COUNT * РАЗМЕР_СТРАНИЦЫ
Количество раз page_count он входит в цикл... он записывает 256 байт за раз, выходит из цикла, для следующего количества страниц снова входит в цикл....

Jochen Arndt

Очень важно, чтобы вы понимали, что делает пример кода. Затем вы должны подумать о том, что вы хотите сделать. Вы можете использовать пример кода в качестве базового, но должны адаптировать его к твой потребности.

Пример кода не обрабатывает данные, загруженные из файла. Он использует (исходный) буфер фиксированного размера MAX_DATA. Вы должны заменить использование этого буфера буфером, содержащим данные файла. Это включает в себя не только сам буфер, но и его размер (MAX_DATA -> размер вашего буфера = размер файла).

Member 13142768

Здравствуйте сэр,
да, я понял, что нужно удалить его для петли. Я пробовал так, как вы сказали, но здесь файл только не открывается. в среде Xilinx sdk я не могу использовать параметры ввода-вывода, они не принимаются. поэтому для аппаратного кода я могу восстановить код только во время отладки...

Jochen Arndt

Из вашего вопроса не было ясно, что вы используете устройство Xilinx. У меня нет опыта общения с ними. Но если это обычное устройство устройства без файловой системы, вы должны передать данные в систему, используя другой метод.

Я предлагаю использовать форумы Xilinx, потому что там вы можете получить лучшую помощь.

Member 13142768

Спасибо Вам большое, сэр, вы проделали действительно большую работу...... Люди ксилинкса не отвечают за это.... поэтому мы попытались выйти наружу...
Теперь также ddr memory writebuffer записывает 256 раз за раз, а память qspi читает. после подсчета 1-й страницы запишите в цикл, во второй цикл....
указатель увеличивается, testaddress увеличивается, bytecount составляет 256 onlt, команда write записывается. но адрес буфера записи(адрес памяти ddr)все тот же. может быть, там у нас возникают проблемы, я думаю.... вы знаете, как это решить????

Jochen Arndt

Вы имеете в виду WriteBuffer?
Этот адрес не должен меняться. Он должен содержать данные для каждой записи страницы, что обеспечивается вызовом memcpy.

Реальный адрес памяти-это nSpiAddress в моем примере. Это начальный адрес, и приращение этого адреса выполняется путем добавления nOffset, который сам увеличивается с каждой итерацией цикла путем добавления PAGE_SIZE.

Member 13142768

Привет,
В моем коде для первого цикла Страницы 256 байт считываются из памяти ddr. для второго подсчета тестовый адрес(адрес назначения) добавляется с помощью (page_size*page_count)+testaddress....
инкремент указателя также отображается, но данные по-прежнему являются теми же самыми первыми 256 байтами....
Не знаю, как это решить.....
void FlashWrite(XQspiPs *QspiPtr, адрес u32, байт-счет u32, команда u8)
{
u8 WriteEnableCmd = { WRITE_ENABLE_CMD };
u8 ReadStatusCmd[] = { READ_STATUS_CMD, 0 }; /* необходимо отправить 2 байта */
u8 FlashStatus[2];

/*
* Отправьте команду write enable на вспышку, чтобы она могла быть
* письменно, это должно быть отправлено как отдельный перевод до того, как
* запись
*/
XQspiPs_PolledTransfer(QspiPtr, &WriteEnableCmd, NULL,
sizeof(WriteEnableCmd));


/*
* Настройте команду записи с указанным адресом и данными для
* ВСПЫШКА
*/
WriteBuffer[COMMAND_OFFSET] = Команда;
WriteBuffer[ADDRESS_1_OFFSET] = (У8)((адрес &усилитель; значение 0xff0000) &ГТ;&ГТ; 16);
WriteBuffer[ADDRESS_2_OFFSET] = (u8)((Address & 0xFF00) >> 8);
WriteBuffer[ADDRESS_3_OFFSET] = (u8)(Address & 0xFF);

/*
* Отправьте команду записи, адрес и данные на флэш-память, чтобы быть
* записано, никакой буфер приема не указан, так как нет ничего, чтобы
* получать
*/
XQspiPs_PolledTransfer(QspiPtr, WriteBuffer, NULL,
ByteCount + OVERHEAD_SIZE);

/*
* Дождитесь завершения команды записи во вспышку, это займет
* некоторое время для записи данных
*/
а (1) {
/*
* Опросите регистр состояния вспышки, чтобы определить, когда она
* завершается отправкой команды read status и получением
* байт состояния
*/
XQspiPs_PolledTransfer(QspiPtr, ReadStatusCmd, FlashStatus,
sizeof(ReadStatusCmd));

/*
* Если состояние указывает на то, что запись завершена, то прекратите ожидание,
* если значение 0xFF в байте состояния считывается из
* устройство и этот цикл никогда не завершаются, выбор ведомого устройства является
* возможно, неверно, так что состояние устройства не отображается.
* читать
*/
if ((FlashStatus[1] & 0x01) == 0) {
перерыв;
}
}
}

Jochen Arndt

Все вышесказанное - это просто код для написания. Если вы передали правильные параметры и скопировали данные для записи в WriteBuffer (используя memcpy), то данные должны быть записаны правильно.