+7(960) 250-82-68 spam@mirossa.ru


  MCU         C           1С         PHP       JAVA      разное 


Статьи
 
 
решение задачи 6.2 по учебнику Discovering the STM32 Microcontroller by Geoffrey Brown

STM32. Запись и чтение из EEPROM 25LC160. Интерфейс SPI. DMA

При нажатии на синюю кнопку пропускаем время дребезга контакта и начинаем процесс записи и чтения. Вначале тестируем отклики модуля памяти на команды. Записываем. Читаем.
Data-sheet 25AA160/25LC160/25C160

Весь исходный код. ide CooCox.

Компоненты:
STM32VLDISCOVERY (stm32F100RBT6)
EEPROM 25LC160/SN (16 Кбит, 2К x 8бит, Serial SPI, 2 МГц, SOIC, 8 вывод)

Соединение: ( см документацию на eeprom. TABLE 2-1)
CS ▶ PC10
SO ▶ PB14
WP ▶ +3.3V
VSS ▶ ground
SI ▶ PB15
SCK ▶ PB13
HOLD ▶ +3.3V
Vcc ▶ +3.3V

connection STM32 and 25LC160

Недостатки реализации:
1. Расчёт на работающее устройство. Если произойдёт отказ модуля памяти, то при выполнении операций с ним выполнение кода зависнет в бесконечном цикле.
2. После настройки и включения SPI дальше я его не выключаю. В RM0041 в главе Serial peripheral interface (SPI) на стр 568 есть раздел 21.3.8 Disabling the SPI и там сказано, что когда передача завершена, то МОЖНО отключить SPI (даны инструкции)... и SPE=0 + отключить тактирование SPI.

Ещё:
DMA для SPI задействуется при передаче/получении больше 4 порций данных (8 или 16 бит).
Решение о включении DMA для SPI принимается в eeprom.c, а не в spi.c.

некоторые модули:

/* main.c */

#include <stm32f10x.h>
#include <stm32f10x_rcc.h>
#include <stm32f10x_gpio.h>
#include <stm32f10x_spi.h>
#include "eeprom.h"
#include <string.h>

// для примера 3
//static uint16_t INbuff[10] = {0xFFF1,0xFFF2,0xFFF3,0xFFF4,0xFFF5,0xFFF6,0xFFF7,0xFFF8,0xFFF9,0xFFFA};
//static uint16_t OUTbuff[10] = {0};

void otherInit(void);

void Delay(uint32_t nTime);
uint8_t debounce(uint8_t last);

#define rlen 100

int main(void)
{
	uint8_t currentButton;
	uint8_t lastButton;

	uint8_t len;
	uint8_t rbuf[rlen], rs;
	//char mes[] = "The Read Status Register (RDSR) instruction provides access to the Status register.";
char mes[] = "Love is the only force capable of transforming an enemy into a friend. Martin Luther King, Jr.";

	lastButton = GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0);
	currentButton = lastButton;

	otherInit(); // Initialize user button
	eepromInit();

	// Configure SysTick Timer
	if (SysTick_Config(SystemCoreClock / 1000))
			while (1);

while (1)	{

	currentButton = debounce(lastButton);

	if ( lastButton == Bit_RESET && currentButton == Bit_SET ){


		// 1. Тест функций.
		//
		rs = eepromReadStatus(); //чтение регистра статуса

		//активация функций записи в модуле памяти перед записью
		eepromWriteEnable();

		while (WIP(rs = eepromReadStatus()));

		//проверка успешного выполнения предыдущей функции по флагу WEL
		if (WEL(rs = eepromReadStatus()))
			eepromWriteDisable(); // деактивация функций записи
		else
			assert_failed(__FILE__, __LINE__);

		while (WIP(rs = eepromReadStatus()));

		//проверка успешности выполнения функции eepromWriteDisable()
		if (!WEL((rs = eepromReadStatus()))){

			// Установка битов BP0 and BP1.
			eepromWriteStatus( (uint8_t)4 | 8); // BP0 | BP1
		} else
			assert_failed(__FILE__, __LINE__);

		while (WIP(rs = eepromReadStatus())); // ожидание окончания записи

		// BP0 и BP1 установлены. Значение регистра статуса - 00001100.
		if ((rs & ( 4 | 8))){ // проверяем, так ли это?


			eepromWriteStatus(0x00); // обнуляем биты BP0 и BP1
		}else
			assert_failed(__FILE__, __LINE__);

		//проверка установки бита WPEN
		eepromWriteStatus( (uint8_t)0x80); // 10000000
		// сброс бита WPEN
		eepromWriteStatus(0x00);
		while (WIP(rs = eepromReadStatus()));

		rs = eepromReadStatus();
		//test. end

		// 2. Запись и чтение
		len = (uint8_t)strlen(mes);
		eepromWrite(mes, len, 4 ); //записать с адреса 4

		eepromRead(rbuf, rlen, 0 ); // прочитать с адреса x00 100 байт


		// 3. копирование данных из памяти в память через DMA.
		// раскомментировать переменные INbuff и OUTbuff
		//xchng_datablock(0, 1, OUTbuff, INbuff, 10);


	}

		lastButton = currentButton;

}//while

    return 0;
}

void otherInit(void){
	GPIO_InitTypeDef GPIO_InitStructure;


	// user button A0
		RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA , ENABLE);
		GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
		GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
		GPIO_Init(GPIOA,	&GPIO_InitStructure);
}

static __IO uint32_t TimingDelay;

void Delay(uint32_t nTime){
	TimingDelay = nTime;
	while(TimingDelay != 0);
}

void SysTick_Handler(void){
	if (TimingDelay != 0x00)
		TimingDelay--;
}

uint8_t debounce(uint8_t last){
	uint8_t current = GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0);
	  if ( last != current ){
		  Delay(5);
		  current = GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0);
	  }
  return current;
}

#ifdef USE_FULL_ASSERT
void assert_failed(uint8_t *file, uint32_t line)
{
	/* Infinite loop */
	/* Use GDB to find out why we're here */
	while (1);
}
#endif


Под отладкой. Прочитанные 80 байт

/* eeprom.h */

#ifndef _EEPROM_
#define _EEPROM_

#include <stm32f10x.h>
#include <stm32f10x_gpio.h>

// настройка для линии ChipSelect
#define EEPROM_PORT GPIOC
#define EEPROM_CS GPIO_Pin_10

#define WIP(x) ((x) & 1) // бит "процесс записи не закончен."
#define WEL(x) ((x) & 2) // бит "включены ли операции записи"

//команды
enum eepromCMD {
	cmdREAD = 0x03,  //читать данные из памяти
	cmdWRITE = 0x02, //записывать данные в память
	cmdWREN = 0x06,  //включение операций записи
	cmdWRDI = 0x04,  //отключение операций записи
	cmdRDSR = 0x05,  //читать регистр статуса
	cmdWRSR = 0x01   //записать в регистр статуса
};

// Инициализация.
// Настройка SPI2 c программной линией ChipSelect, включение тактирования для DMA1
void eepromInit(void);

//в этом модуле памяти есть регистр статуса. Его биты:
// 0 - WIP  // запись в процессе выполнения
// 1 - WEL  // "защёлка" включения записи.
// 2 - BPO  // защита блока памяти от записи
// 3 - BP1  // защита блока памяти от записи
// 4 - -
// 5 - -
// 6 - -
// 7 - WPEN // защита от перезаписи энергонезависимых битов в регистре статуса

//WIP, WEL - только чтение
//BPO, BP1, WPEN - чтение и запись, Энергонезависимые.

//Перед каждой операцией записи (данных в модуль памяти или записи в
//регистр статуса) нужно устанавливать бит WEL в регистре статуса. Деляется это
// отправкой команды WREN.
// Этот бит сбрасывается самим модулем памяти в случае успешного выполнения
// команд: WRDI, WRSR, WRITE.
// (вызывать эту функцию перед вызовом функций eepromWriteStatus() и eepromWrite()
//  не нужно - вызов используется внутри них)
void eepromWriteEnable(void);

//то же, что и eepromWriteEnable(), только наоборот (выключение).
void eepromWriteDisable(void);

//прочитать регистр статуса
// возврат: значение регистра статуса
uint8_t eepromReadStatus(void);

//отправка команды WRSR.
//записать в регистр статуса новые значения битов BP0 и BP1 для выбора одного
//из четырёх "уровней" защиты массива памяти.
//"уровни":
// _BP1__BP0
// 1. 0  0  - нет защиты
// 2. 0  1  - защита верхней 1/4 памяти ( 0600h - 07FFh)
// 3. 1  0  - защита верхней 1/2 памяти ( 0400h - 07FFh)
// 4. 1  1  - защита всей памяти ( 0000h - 07FFh)
void eepromWriteStatus(uint8_t status);

//Запись данных в модуль памяти.
// buf - указатель на данные
// cnt - количество байт
// offset - начальный адрес в массиве памяти
int eepromWrite(uint8_t *buf, uint8_t cnt, uint16_t offset);

//Чтение данных из модуля памяти.
// buf - куда читать
// cnt - количество байт
// offset - начальный адрес в массиве памяти
int eepromRead(uint8_t *buf, uint8_t cnt, uint16_t offset);

// в dataSheet 25AA160/25LC160/25C160 в таблице
// TABLE 3-3: WRITE-PROTECT FUNCTIONALITY MATRIX
// приведены все сочетания битов WPEN и WEL и пина WP для выбора
// различных возможностей защиты от записи.
// (в моём случае пин WP был всегда соединён с "+".)
#endif


/* spi.h */

#ifndef SPI_H_
#define SPI_H_

enum spiSpeed { SPI_SLOW, SPI_MEDIUM, SPI_FAST };

// Основная настройка SPI. Работает только с SPI2.
void spiInit(SPI_TypeDef* SPIx);

// Передача/получение данных по 8 бит
// SPIx - только SPI2
// rbuf - указатель на буфер, куда будут загружены данные
// tbuf - указатель на отправляемые данные

// cnt - количество (по 8 бит)
//
// Если в tbuf передан указатель, а в rbuf - 0, то будут отправлены данные, а получаемые
//  данные никуда записываться не будут.
// Если наоборот - будут получены данные, отправляться будет "пустой" сигнал (0xff).
// Если оба указателя не нулевые, то данные будут переданы и получены.
int spiReadWrite(SPI_TypeDef* SPIx, uint8_t * rbuf, const uint8_t * tbuf, int cnt, enum spiSpeed speed);

// Передача/получение данных по 16 бит
// см. описание функции spiReadWrite()  (8 бит -> 16 бит)
int spiReadWrite16(SPI_TypeDef* SPIx, uint16_t * rbuf, const uint16_t * tbuf, int cnt, enum spiSpeed speed);

#endif


/* spi_dma.h */

#ifndef SPI_DMA_H_
#define SPI_DMA_H_

#include <stm32f10x.h>

// Инициализация. Включение тактирования
void spi_dma_Init(void);

//Передача/Получение данных по SPI c DMA
//(основные настройки SPI должны быть уже выполнены (spi.h.c) )
// SPIx - SPI1 или SPI2
// half: 0 - 8 бит, 1 - 16 бит
// tbuf - указатель на отправляемые данные
// rbuf - указатель на буфер, куда будут загружены данные
// count - количество порций данных размером по параметру half
//
// Если в tbuf передан указатель, а в rbuf - 0, то будет запущена фукнция отправки.
// Если наоборот - будет запущена функция получения.
// Если оба указателя не нулевые, то будет запущено копирование из памяти в память
int xchng_datablock(SPI_TypeDef *SPIx , uint8_t half , const void *tbuf , void *rbuf , unsigned count);

#endif

Комментарии

#15 Дукас 2023-11-14 12:25:57

А, где все *.c файлы?




information