|
|
  |
Память M95-256, stm32f100+M95-256 |
|
|
|
Apr 12 2016, 12:23
|

Частый гость
 
Группа: Участник
Сообщений: 164
Регистрация: 12-04-16
Из: Белгород
Пользователь №: 91 250

|
Ребята, доброго времени суток) Бьюсь над памятью М95-256. Пишу на Си. МК -stm32f100. Хочу просто считать статусный регистр. Документация мною более-менее изучена. Не могу понять, где ошибка. Почему возвращает 255... иногда 7 возвращается. Может кто-то работал с этой зверь-машиной? Может неверный алгоритм, код, какой-то вообще левый косяк? Я в начинающих пока что. Соображаю медленно.
#include <stm32f10x.h> #include <stm32f10x_gpio.h> #include <stm32f10x_rcc.h> #include <stm32f10x_spi.h> #include <misc.h>
#define S GPIO_Pin_4 #define Port GPIOA #define D GPIO_Pin_7 #define Q GPIO_Pin_6 #define C GPIO_Pin_5 #define W GPIO_Pin_2 #define HOLD GPIO_Pin_3
void RDSR() { Port->ODR|=W; Port->ODR&=~S; SPI_I2S_SendData(SPI1,0b00000101); Port->ODR|=S; }
int main(void) { SPI_Master_Conf(); RDSR(); while(1); }
void SPI_Master_Conf() { RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);
GPIO_InitTypeDef port; port.GPIO_Mode = GPIO_Mode_AF_PP; port.GPIO_Pin = C|Q|D; port.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(Port, &port);
GPIO_InitTypeDef port1; port1.GPIO_Mode = GPIO_Mode_Out_PP; port1.GPIO_Pin = W|S|HOLD; port1.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(Port, &port1);
Port->ODR|=S; Port->ODR&=~(HOLD|W);
SPI_InitTypeDef spi; SPI_StructInit(&spi); spi.SPI_Direction = SPI_Direction_2Lines_FullDuplex; spi.SPI_Mode = SPI_Mode_Master; spi.SPI_DataSize = SPI_DataSize_8b; spi.SPI_CPOL = SPI_CPOL_Low; spi.SPI_CPHA = SPI_CPHA_2Edge; spi.SPI_NSS = SPI_NSS_Soft; spi.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4; spi.SPI_FirstBit = SPI_FirstBit_MSB; spi.SPI_CRCPolynomial = 7; SPI_Init(SPI1, &spi); SPI_I2S_ITConfig(SPI1, SPI_I2S_IT_RXNE, ENABLE); SPI_I2S_ClearITPendingBit(SPI1,SPI_I2S_IT_RXNE); NVIC_EnableIRQ(SPI1_IRQn); SPI_Cmd(SPI1, ENABLE); }
u32 answer=0; void SPI1_IRQHandler() { if(SPI_I2S_GetITStatus(SPI1,SPI_I2S_IT_RXNE)==1) { SPI_I2S_ClearITPendingBit(SPI1,SPI_I2S_IT_RXNE); answer=(u32)SPI_I2S_ReceiveData(SPI1); }
}
Сообщение отредактировал Ekka - Apr 12 2016, 12:25
|
|
|
|
|
Apr 13 2016, 06:25
|

Частый гость
 
Группа: Участник
Сообщений: 164
Регистрация: 12-04-16
Из: Белгород
Пользователь №: 91 250

|
Цитата(AHTOXA @ Apr 12 2016, 16:15)  Не вижу включения тактирования AFIO. Это тактирование альтернативных функций. Нужно почти всегда. Добавьте в начало что-то вроде RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); Добавила. Но что-то не помогло. Где-то в другом косяк...
|
|
|
|
|
Apr 13 2016, 09:15
|

фанат дивана
     
Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684

|
Вы вообще неправильно работаете с SPI. SPI_I2S_SendData(); - просто записывает байт в регистр передатчика. После надо опрашивать статус, чтобы узнать, когда данные отправятся. (Удобно ждать, когда взведётся бит RXNE). Перед снятием CS надо подождать ещё немножко, потому что флаг RXNE может взводиться немного раньше, чем завершается передача байта. Ногу MISO я конфигурирую не как PUSH-PULL, а как INPUT. Прерывание пока уберите, сделайте просто опросом: Код unsigned char SpiRw(unsigned char out) { SPI_I2S_SendData(SPI1,out); while (!(SPI_I2S_GetITStatus(SPI1,SPI_I2S_IT_RXNE)); return SPI_I2S_ReceiveData(SPI1);; }
void smallDelay() { volatile int i; for (i = 0; i < 100; ++i) {} }
unsigned char RDSR() { unsigned char ret; Port->ODR|=W; Port->ODR&=~S; ret = SpiRw(0b00000101); smallDelay(); Port->ODR|=S; return ret; }
--------------------
Если бы я знал, что такое электричество...
|
|
|
|
|
Apr 13 2016, 11:28
|

Частый гость
 
Группа: Участник
Сообщений: 164
Регистрация: 12-04-16
Из: Белгород
Пользователь №: 91 250

|
Хм... ща попробуем
Спасибо Вам за ответы)))
Вот думаю... может я неправильно подключила.... У меня память М95-256. Есть у нее вход-Q, выход - D, выбор чипа S, С- тактирование. согласно с принципами SPI, MOSI соединяю c Q, MISO - c D, CS - S, NSS - C... HOLD и W - настраиваю как выходы, кидаю на свободные пины.
Хм.... почему же на MISO мк висит единица, просто единица... 255 гонит и все тут. Хотя команда проходит
|
|
|
|
|
Apr 13 2016, 12:06
|

Частый гость
 
Группа: Участник
Сообщений: 164
Регистрация: 12-04-16
Из: Белгород
Пользователь №: 91 250

|
А так можно написать?
#include <stm32f10x.h> #include <stm32f10x_gpio.h> #include <stm32f10x_rcc.h> #include <stm32f10x_spi.h> #include <misc.h>
#define Port GPIOA //Основной порт #define S GPIO_Pin_4 //Выбор чипа #define D GPIO_Pin_7 //Вход(куда приходят данные) #define Q GPIO_Pin_6 //Выход(откуда уходят данные) #define C GPIO_Pin_5 //Сигналы синхронизации (таймер тактирования) #define W GPIO_Pin_2 //Защита от записи #define HOLD GPIO_Pin_3 //Удержание устройства (останов без сброса)
void SPI_Master_Conf(); void delay(int volatile ms); void WRITE(u16 adress, u8 data); void READ(u16 adress); void WREN(); void WRDI(); unsigned char RDSR(); u8 answer=0; int main(void) { SPI_Master_Conf(); answer=RDSR(); while(1); }
unsigned char RDSR() { Port->ODR&=~S; SPI_I2S_SendData(SPI1,0x05); delay(100); Port->ODR|=S; while(!(SPI_I2S_GetITStatus(SPI1,SPI_I2S_IT_RXNE))); SPI_I2S_ClearITPendingBit(SPI1,SPI_I2S_IT_RXNE); return SPI_I2S_ReceiveData(SPI1); }
void SPI_Master_Conf() { RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);
GPIO_InitTypeDef port; port.GPIO_Mode = GPIO_Mode_AF_PP; port.GPIO_Pin = C|Q; port.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(Port, &port);
GPIO_InitTypeDef port1; port1.GPIO_Mode = GPIO_Mode_Out_PP; port1.GPIO_Pin =S|W|HOLD; port1.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(Port, &port1);
GPIO_InitTypeDef port2; port2.GPIO_Mode = GPIO_Mode_IPU; port2.GPIO_Pin =D; port2.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(Port, &port2);
Port->ODR|=S; Port->ODR&=~(HOLD|W);
SPI_InitTypeDef spi; SPI_StructInit(&spi); spi.SPI_Direction = SPI_Direction_2Lines_FullDuplex; spi.SPI_Mode = SPI_Mode_Master; spi.SPI_DataSize = SPI_DataSize_8b; spi.SPI_CPOL = SPI_CPOL_High; spi.SPI_CPHA = SPI_CPHA_2Edge; spi.SPI_NSS = SPI_NSS_Soft; spi.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4; spi.SPI_FirstBit = SPI_FirstBit_MSB; spi.SPI_CRCPolynomial = 7; SPI_Init(SPI1, &spi); SPI_I2S_ITConfig(SPI1, SPI_I2S_IT_RXNE, ENABLE); SPI_I2S_ClearITPendingBit(SPI1,SPI_I2S_IT_RXNE); SPI_Cmd(SPI1, ENABLE); }
|
|
|
|
|
Apr 13 2016, 12:25
|

фанат дивана
     
Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684

|
Цитата(Ekka @ Apr 13 2016, 17:06)  unsigned char RDSR() { Port->ODR&=~S; SPI_I2S_SendData(SPI1,0x05); delay(100); Port->ODR|=S; Так делать неправильно. Вы же не знаете, успел ли за 100 чего-то приняться ответный байт. Для этого и существуют флаги статуса. Записали, подождали установления статуса RXNE - считали ответ. Потом маленькая задержка (чтобы точно передался последний бит), и можно сбрасывать выбор кристалла. Цитата(Ekka @ Apr 13 2016, 17:06)  SPI_I2S_ClearITPendingBit(SPI1,SPI_I2S_IT_RXNE); Это уже лишнее. Бит RXNE сбрасывается чтением регистра данных (SPI_I2S_ReceiveData(SPI1)) И ещё вы забыли убрать включение прерывания: Цитата(Ekka @ Apr 13 2016, 17:06)  SPI_I2S_ITConfig(SPI1, SPI_I2S_IT_RXNE, ENABLE); SPI_I2S_ClearITPendingBit(SPI1,SPI_I2S_IT_RXNE); Кстати, я ещё вот что подумал. Наверное, сначала надо передать команду, а уже только потом микросхема памяти сможет отправить ответ. В этом случае надо для чтения статуса послать второй байт: Код unsigned char RDSR() { unsigned char ret; Port->ODR|=W; Port->ODR&=~S; SpiRw(0b00000101); // передаём команду ret = SpiRw(0); // читаем ответ smallDelay(); Port->ODR|=S; return ret; } ЗЫ. Для оформления кода пользуйтесь кнопкой код:
--------------------
Если бы я знал, что такое электричество...
|
|
|
|
|
Apr 13 2016, 12:46
|

Частый гость
 
Группа: Участник
Сообщений: 164
Регистрация: 12-04-16
Из: Белгород
Пользователь №: 91 250

|
если я убираю это. Цикл WHILE , который ждет, пока установится флаг RXNE виснет. Код SPI_I2S_ITConfig(SPI1, SPI_I2S_IT_RXNE, ENABLE); Немного не поняла...зачем отправлять ВТОРОЙ байт? Я же отправляю команду - СЧИТАТЬ РЕГИСТР. Разве не должен сразу приходить ответный байт? Что означает второй байт? О_О и еще вопрос. Почему чип сбрасываем только после того, как примем ответ? Разве выбор чипа не сбрасывают после завершения каждой команды? Или мы его сбрасываем только после окончания вообще работы с микросхемой памяти? Теперь микросхема отвечает просто нулем. Не могу понять, в документации вроде все так просто. Выбираем чип, отправляем команду считать регистр, сбрасываем чип, считываем ответ.
|
|
|
|
|
Apr 13 2016, 13:25
|

фанат дивана
     
Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684

|
Цитата(Ekka @ Apr 13 2016, 17:46)  если я убираю это. Цикл WHILE , который ждет, пока установится флаг RXNE виснет. Вряд ли это связано. Предполагаю, что вы смотрите регистры отладчиком, отладчик считывает регистр данных, и этим сбрасываете флаг RXNE. Цитата(Ekka @ Apr 13 2016, 17:46)  Немного не поняла...зачем отправлять ВТОРОЙ байт? Я же отправляю команду - СЧИТАТЬ РЕГИСТР. Разве не должен сразу приходить ответный байт? Что означает второй байт? О_О Ну вы же сами вот пишете: Цитата(Ekka @ Apr 13 2016, 17:46)  в документации вроде все так просто. Выбираем чип, отправляем команду считать регистр, сбрасываем чип, считываем ответ.  Видите, сначала надо отправить команду, и только потом считать ответ. Поскольку контроллер является мастером, для считывания ответа он должен выдавать тактирование (CLK). А для этого надо записать что-то в регистр данных. Вот и появляется второй байт. Цитата(Ekka @ Apr 13 2016, 17:46)  и еще вопрос. Почему чип сбрасываем только после того, как примем ответ? Разве выбор чипа не сбрасывают после завершения каждой команды? Или мы его сбрасываем только после окончания вообще работы с микросхемой памяти? Тут я не могу сказать, я не знаю, что у вас за память. Делайте, как написано в документации.
--------------------
Если бы я знал, что такое электричество...
|
|
|
|
|
Apr 14 2016, 08:07
|

Частый гость
 
Группа: Участник
Сообщений: 164
Регистрация: 12-04-16
Из: Белгород
Пользователь №: 91 250

|
Спасибо за Ваши ответы))) Микросхема начала отвечать. Присылает байт статуса. НО. Не могу его правильно считать. При установке ожидания флага (цикл while) все глохнет. Без него на осциллографе видно, что ответ приходит. Но считать его отчего-то не получается. В отладке считываю иногда число 12. В реальном времени считывается 255. Хотя осциллограф показывает, что пин входных данных явно не в единице. вот код, с которым микросхема отвечает. Код void RDSR() { Port->ODR&=~S; SPI_I2S_SendData(SPI1,0b00000101); SPI_I2S_SendData(SPI1,0x0); SPI_I2S_SendData(SPI1,0x0); // while((SPI_I2S_GetITStatus(SPI1,SPI_I2S_IT_RXNE)==0)); answer=SPI_I2S_ReceiveData(SPI1); Port->ODR|=S; } функция просто постоянно крутится в вечном цикле в мэине
|
|
|
|
|
Apr 14 2016, 08:40
|

Знающий
   
Группа: Участник
Сообщений: 756
Регистрация: 14-11-14
Пользователь №: 83 663

|
Цитата(Ekka @ Apr 13 2016, 15:28)  Хм... ща попробуем
Спасибо Вам за ответы)))
Вот думаю... может я неправильно подключила.... У меня память М95-256. Есть у нее вход-Q, выход - D, выбор чипа S, С- тактирование. согласно с принципами SPI, MOSI соединяю c Q, MISO - c D, CS - S, NSS - C... HOLD и W - настраиваю как выходы, кидаю на свободные пины.
Хм.... почему же на MISO мк висит единица, просто единица... 255 гонит и все тут. Хотя команда проходит Разрешите встрять? Спасибо (: Так вот: смотрим в datasheet и видим D - Serial Data Input - Input Q - Serial Data Output - Output Попутали, Ekka, вход и выход у памяти - этим и объясняется дикое поведение. Даже чисто мнемонически, на картинке (как по ГОСТу) входы - слева, выход - справа. В контроллере MISO - настраивать как ВХОД; MOSI - настраивать как PUSH-PULL.
--------------------
Пролетарий умственного труда.
|
|
|
|
|
Apr 14 2016, 09:20
|

Частый гость
 
Группа: Участник
Сообщений: 164
Регистрация: 12-04-16
Из: Белгород
Пользователь №: 91 250

|
Цитата(Obam @ Apr 14 2016, 09:40)  Разрешите встрять? Спасибо (:
Так вот: смотрим в datasheet и видим D - Serial Data Input - Input Q - Serial Data Output - Output
Попутали, Ekka, вход и выход у памяти - этим и объясняется дикое поведение. Даже чисто мнемонически, на картинке (как по ГОСТу) входы - слева, выход - справа. В контроллере MISO - настраивать как ВХОД; MOSI - настраивать как PUSH-PULL. Код #include <stm32f10x.h> #include <stm32f10x_gpio.h> #include <stm32f10x_rcc.h> #include <stm32f10x_spi.h> #include <misc.h>
#define Port GPIOA //Основной порт #define S GPIO_Pin_4 //Выбор чипа #define MISO GPIO_Pin_6 //Вход(куда приходят данные) #define MOSI GPIO_Pin_7 //Выход(откуда уходят данные) #define SCK GPIO_Pin_5 //Сигналы синхронизации (таймер тактирования) #define W GPIO_Pin_2 //Защита от записи #define HOLD GPIO_Pin_3 //Удержание устройства (останов без сброса)
void SPI_Master_Conf(); void RDSR(); void delay(int ms) { int a=0; for(a=0;a<ms;a++); }
int main(void) { SPI_Master_Conf();
while(1){ RDSR();
} }
u16 answer=0; void RDSR() { Port->ODR&=~S; SPI_I2S_SendData(SPI1,0b00000101); SPI_I2S_SendData(SPI1,0b00000000); SPI_I2S_SendData(SPI1,0b00000000); // while((SPI_I2S_GetITStatus(SPI1,SPI_I2S_IT_RXNE)==0)); answer=SPI_I2S_ReceiveData(SPI1); Port->ODR|=S; }
void SPI_Master_Conf() { RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);
GPIO_InitTypeDef port; port.GPIO_Mode = GPIO_Mode_AF_PP; port.GPIO_Pin = SCK|MOSI; port.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(Port, &port);
GPIO_InitTypeDef port1; port1.GPIO_Mode = GPIO_Mode_Out_PP; port1.GPIO_Pin =S|W|HOLD; port1.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(Port, &port1);
GPIO_InitTypeDef port2; port2.GPIO_Mode = GPIO_Mode_IN_FLOATING; port2.GPIO_Pin =MISO; port2.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(Port, &port2);
Port->ODR|=(S|HOLD|W);
SPI_InitTypeDef spi; SPI_StructInit(&spi); spi.SPI_Direction = SPI_Direction_2Lines_FullDuplex; spi.SPI_Mode = SPI_Mode_Master; spi.SPI_DataSize = SPI_DataSize_8b; spi.SPI_CPOL = SPI_CPOL_Low; spi.SPI_CPHA = SPI_CPHA_2Edge; spi.SPI_NSS = SPI_NSS_Soft; spi.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256; spi.SPI_FirstBit = SPI_FirstBit_MSB; spi.SPI_CRCPolynomial = 7; SPI_Init(SPI1, &spi); SPI_Cmd(SPI1, ENABLE); } так что ли? Но память один фиг не отвечает. Ну что ж я не так делаю... на осциллографе даже нет признаков жизни. На входе МК же должен быть ответ памяти, да? Там тупо 0. Тогда почему в answer 255... чет я запуталась вкорень Может, она того.... сгорела  Может, я неправильно W и HOLD настроила? Они же должны быть в единицах? Если HOLD опущу - будет пауза. Если W опущу, установлю защиту от записи. Или я опять что-то путаю. Может, кто делал такую штуку и есть хоть похожий пример?
|
|
|
|
|
Apr 14 2016, 09:38
|

Частый гость
 
Группа: Участник
Сообщений: 164
Регистрация: 12-04-16
Из: Белгород
Пользователь №: 91 250

|
Цитата(Obam @ Apr 14 2016, 10:28)  Кодом в меня тыкать не надо (:
Смысл моего замечания таков: физически MOSI разведён на Q? физически MISO разведён на D? Если так, то хоть обпереопределяйся - лажа не исправится. Нет... у меня физически MISO разведен на Q, а MOSI - на D. подключено вроде все правильно...уже несколько раз перепроверено(
|
|
|
|
|
Apr 14 2016, 10:16
|

Частый гость
 
Группа: Участник
Сообщений: 164
Регистрация: 12-04-16
Из: Белгород
Пользователь №: 91 250

|
Спасибо за разъяснение, Obam, т.е. функция должна быть такой??? Код Port->ODR&=~S; //выбираем чип SPI_I2S_SendData(SPI1,0b00000101); //команда СЧИТАТЬ РЕГИСТР while((SPI_I2S_GetITStatus(SPI1,SPI_I2S_IT_TXE)==0));//ждем, пока данные отправятся SPI_I2S_SendData(SPI1,0b00000000); //отправляем пустую команду, чтобы считать байт while((SPI_I2S_GetITStatus(SPI1,SPI_I2S_IT_TXE)==0)); //ждем, пока отправится while((SPI_I2S_GetITStatus(SPI1,SPI_I2S_IT_RXNE)==0)); //ждем, когда можно будет считать answer=SPI_I2S_ReceiveData(SPI1);//считываем байт Port->ODR|=S; //сброс чипа что-то тут не так... ждем много. И там ли я поставила ожидание. А если просто не сбрасывать чип и сделать так? Код Port->ODR&=~S; //выбираем чип SPI_I2S_SendData(SPI1,0b00000101); //команда СЧИТАТЬ РЕГИСТР while((SPI_I2S_GetITStatus(SPI1,SPI_I2S_IT_TXE)==0));//ждем, пока данные отправятся while((SPI_I2S_GetITStatus(SPI1,SPI_I2S_IT_RXNE)==0)); //ждем, когда можно будет считать answer=SPI_I2S_ReceiveData(SPI1);//считываем байт
|
|
|
|
|
Apr 14 2016, 11:01
|

Знающий
   
Группа: Участник
Сообщений: 756
Регистрация: 14-11-14
Пользователь №: 83 663

|
Цитата(Ekka @ Apr 14 2016, 14:16)  Спасибо за разъяснение, Obam, т.е. функция должна быть такой??? Код Port->ODR&=~S; //выбираем чип SPI_I2S_SendData(SPI1,0b00000101); //команда СЧИТАТЬ РЕГИСТР while((SPI_I2S_GetITStatus(SPI1,SPI_I2S_IT_TXE)==0));//ждем, пока данные отправятся SPI_I2S_SendData(SPI1,0b00000000); //отправляем пустую команду, чтобы считать байт while((SPI_I2S_GetITStatus(SPI1,SPI_I2S_IT_TXE)==0)); //ждем, пока отправится while((SPI_I2S_GetITStatus(SPI1,SPI_I2S_IT_RXNE)==0)); //ждем, когда можно будет считать answer=SPI_I2S_ReceiveData(SPI1);//считываем байт Port->ODR|=S; //сброс чипа что-то тут не так... ждем много. И там ли я поставила ожидание. Ну ё-моё ): разъяснение не подействовало? Код Port->ODR&=~S; //выбираем чип SPI_I2S_SendData(SPI1,0b00000101); //команда СЧИТАТЬ РЕГИСТР while((SPI_I2S_GetITStatus(SPI1,SPI_I2S_IT_RXNE)==0));//ждем, пока данные отправятся и можно будет считать answer=SPI_I2S_ReceiveData(SPI1);//считываем байт - здесь фиктивный
SPI_I2S_SendData(SPI1,0b00000000); //отправляем пустую команду, чтобы считать байт while((SPI_I2S_GetITStatus(SPI1,SPI_I2S_IT_RXNE)==0)); //ждем, пока отправится и можно будет считать answer=SPI_I2S_ReceiveData(SPI1);//считываем байт Port->ODR|=S; //сброс чипа Вы картиночку Fig.225 на стр.524 в cd00246267.pdf видели?
--------------------
Пролетарий умственного труда.
|
|
|
|
|
Apr 14 2016, 11:57
|

Знающий
   
Группа: Участник
Сообщений: 756
Регистрация: 14-11-14
Пользователь №: 83 663

|
Цитата(Ekka @ Apr 14 2016, 15:14)  Да. Но с пониманием туго(  Так приложите к ней рисунок со стр. 19 из CD00103810.pdf: SCK это C, MOSI это D, MISO это Q. Байт положили в DR, он автоматом переносится в сдвиговый регистр и начинает побитно отправляться ведомому; при этом ведомый побитно отдаёт свой байт ведущему. Все биты переданы (а соответственно и приняты) - тогда выставляется флаг RXNE => можно считать полученное.
--------------------
Пролетарий умственного труда.
|
|
|
|
|
Apr 14 2016, 12:42
|

Частый гость
 
Группа: Участник
Сообщений: 164
Регистрация: 12-04-16
Из: Белгород
Пользователь №: 91 250

|
Цитата(Obam @ Apr 14 2016, 12:57)  Так приложите к ней рисунок со стр. 19 из CD00103810.pdf: SCK это C, MOSI это D, MISO это Q.
Байт положили в DR, он автоматом переносится в сдвиговый регистр и начинает побитно отправляться ведомому; при этом ведомый побитно отдаёт свой байт ведущему. Все биты переданы (а соответственно и приняты) - тогда выставляется флаг RXNE => можно считать полученное. Только чур камнями не бросать) Тогда выходит сначала я кладу в DR регистр мою команду, потом жду пока TXE флаг установится, потом передаю пустой байт, потом жду пока RXNE флаг установится, и забираю ответный байт?
|
|
|
|
|
Apr 14 2016, 12:49
|

Знающий
   
Группа: Участник
Сообщений: 756
Регистрация: 14-11-14
Пользователь №: 83 663

|
Цитата(Ekka @ Apr 14 2016, 16:42)  Только чур камнями не бросать) Тогда выходит сначала я кладу в DR регистр мою команду, потом жду пока TXE флаг установится, потом передаю пустой байт, потом жду пока RXNE флаг установится, и забираю ответный байт? Не надо TXE сейчас использовать. Ваши действия таковы: "сначала я кладу в DR регистр мою команду, потом жду пока RXNE флаг установится, забираю фиктивный ответный байт потом передаю пустой байт, потом жду пока RXNE флаг установится, и забираю ответный байт? " В посте #19 уже и код был приведён.
--------------------
Пролетарий умственного труда.
|
|
|
|
|
Apr 14 2016, 13:12
|

Знающий
   
Группа: Участник
Сообщений: 756
Регистрация: 14-11-14
Пользователь №: 83 663

|
Цитата(Ekka @ Apr 14 2016, 17:05)  Нет... что-то не так. Микросхема не отвечает. Хотя байты передаются. Микросхему проверили, протестили, рабочая, с др.устройством все прекрасно отвечает... хмм С каким "др.устройством все прекрасно отвечает"? Телепаты в отпуске (; Цитата Почему TXE сейчас не используем? ТXE - это флаг пустого DR, но не пустого сдвигового регистра; используется для того чтобы повысить пропускную способность SPI. На рис. 225 всё "до тла" разжёвано.
--------------------
Пролетарий умственного труда.
|
|
|
|
|
Apr 15 2016, 07:24
|

Частый гость
 
Группа: Участник
Сообщений: 164
Регистрация: 12-04-16
Из: Белгород
Пользователь №: 91 250

|
Код #include <stm32f10x.h> #include <stm32f10x_gpio.h> #include <stm32f10x_rcc.h> #include <stm32f10x_spi.h> #include <misc.h>
#define Port GPIOA //Основной порт #define S GPIO_Pin_4 //Выбор чипа #define MISO GPIO_Pin_6 //Вход(куда приходят данные) #define MOSI GPIO_Pin_7 //Выход(откуда уходят данные) #define SCK GPIO_Pin_5 //Сигналы синхронизации (таймер тактирования) #define W GPIO_Pin_2 //Защита от записи #define HOLD GPIO_Pin_3 //Удержание устройства (останов без сброса)
void SPI_Master_Conf(); void RDSR(); void WREN(); void WRSR(u8 data); void WRDI();
int main(void) { SPI_Master_Conf(); WREN(); WRSR(0x8); WRDI(); while(1) { RDSR(); } }
u16 answer=255; u16 err=255; void RDSR() { Port->ODR&=~S; //выбираем чип while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_BSY) == 1); //ждем, пока передатчик занят SPI_I2S_SendData(SPI1,0x05); //команда СЧИТАТЬ РЕГИСТР while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_BSY) == 1); //ждем, пока передатчик занят err=SPI_I2S_ReceiveData(SPI1); //считываем байт - здесь фиктивны
while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_BSY) == 1); //ждем, пока передатчик занят SPI_I2S_SendData(SPI1,0b11111111); //отправляем пустую команду, чтобы считать байт while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_BSY) == 1); //ждем, пока передатчик занят answer=SPI_I2S_ReceiveData(SPI1); //считываем байт Port->ODR|=S; //сброс чипа }
void WRSR(u8 data) { Port->ODR&=~S; //выбираем чип while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_BSY) == 1); //ждем, пока передатчик занят SPI_I2S_SendData(SPI1,0b00000001); //команда запись РЕГИСТРA while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_BSY) == 1); //ждем, пока передатчик занят SPI_I2S_SendData(SPI1,data); //передаем новое значение регистра while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_BSY) == 1); //ждем, пока передатчик занят Port->ODR|=S; //сброс чипа } void WREN() { Port->ODR&=~S; //выбираем чип while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_BSY) == 1); //ждем, пока передатчик занят SPI_I2S_SendData(SPI1,0b00000110); //команда разрешить запись - установить WEL бит while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_BSY) == 1); //ждем, пока передатчик занят Port->ODR|=S; //сброс чипа }
void WRDI() { Port->ODR&=~S; //выбираем чип while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_BSY) == 1); //ждем, пока передатчик занят SPI_I2S_SendData(SPI1,0b00000100); //команда отмена рарешения записи while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_BSY) == 1); //ждем, пока передатчик занят Port->ODR|=S; //сброс чипа }
void SPI_Master_Conf() { RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);
GPIO_InitTypeDef port; port.GPIO_Mode = GPIO_Mode_AF_PP; port.GPIO_Pin = SCK|MOSI; port.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(Port, &port);
GPIO_InitTypeDef port1; port1.GPIO_Mode = GPIO_Mode_Out_PP; port1.GPIO_Pin =S|W|HOLD; port1.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(Port, &port1); Port->ODR|=(S|HOLD|W);
GPIO_InitTypeDef port2; port2.GPIO_Mode = GPIO_Mode_IN_FLOATING; port2.GPIO_Pin =MISO; port2.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(Port, &port2);
SPI_InitTypeDef spi; SPI_StructInit(&spi); spi.SPI_Direction = SPI_Direction_2Lines_FullDuplex; spi.SPI_Mode = SPI_Mode_Master; spi.SPI_DataSize = SPI_DataSize_8b; spi.SPI_CPOL = SPI_CPOL_High; spi.SPI_CPHA = SPI_CPHA_2Edge; spi.SPI_NSS = SPI_NSS_Soft; spi.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256; spi.SPI_FirstBit = SPI_FirstBit_MSB; spi.SPI_CRCPolynomial = 7; SPI_Init(SPI1, &spi); SPI_NSSInternalSoftwareConfig(SPI1, SPI_NSSInternalSoft_Set); SPI_Cmd(SPI1, ENABLE); } почему-то так все работает.... спасибо всем за подсказки, ребята)) и за доходчивые и конкретные объяснения)
|
|
|
|
|
May 17 2016, 07:41
|

Частый гость
 
Группа: Участник
Сообщений: 164
Регистрация: 12-04-16
Из: Белгород
Пользователь №: 91 250

|
Ребята, снова стучу в эту тему((( Недавно обнаружила, что SPI у меня только один раз нормально считывает, а дальше либо какая-то чушь, либо неправильно. Проблема в том, что какой адрес я бы не задавала, например в цикле 10 раз считать по адресу 0х00, возвращается в ответ строка с разными символами, а должны же быть одни и те же. Задаю разные адреса, а приходит одна и та же строка в ответ. Кто-нибудь знает в чем моя проблема... вот настройка SPI2 Код void SPI_Master_Config() { RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE);
GPIO_InitTypeDef port; port.GPIO_Mode = GPIO_Mode_AF_PP; port.GPIO_Pin = SCK|MOSI; port.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(Port, &port);
GPIO_InitTypeDef port1; port1.GPIO_Mode = GPIO_Mode_Out_PP; port1.GPIO_Pin =S; port1.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(Port, &port1); Port->ODR|=S;
GPIO_InitTypeDef port2; port2.GPIO_Mode = GPIO_Mode_IN_FLOATING; port2.GPIO_Pin =MISO; port2.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(Port, &port2);
SPI_InitTypeDef spi; SPI_StructInit(&spi); spi.SPI_Direction = SPI_Direction_2Lines_FullDuplex; spi.SPI_Mode = SPI_Mode_Master; spi.SPI_DataSize = SPI_DataSize_8b; spi.SPI_CPOL = SPI_CPOL_High; spi.SPI_CPHA = SPI_CPHA_2Edge; spi.SPI_NSS = SPI_NSS_Soft; spi.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256; spi.SPI_FirstBit = SPI_FirstBit_MSB; spi.SPI_CRCPolynomial = 7; SPI_I2S_ITConfig(SPI2,SPI_I2S_IT_RXNE,ENABLE); SPI_I2S_ITConfig(SPI2,SPI_I2S_IT_TXE,ENABLE); SPI_Init(SPI2, &spi); SPI_Cmd(SPI2, ENABLE); } Вот опрос микросхемы памяти: Код u8 READ(u16 adress) { Port->ODR&=~S;
SPI_I2S_SendData(SPI2,0b00000011); while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_BSY) == 1);
SPI_I2S_SendData(SPI2,adress); while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_BSY) == 1);
SPI_I2S_SendData(SPI2,0b00000000); while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_BSY) == 1);
err=SPI_I2S_ReceiveData(SPI2);
while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_BSY) == 1); SPI_I2S_SendData(SPI2,0b00000000); while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_BSY) == 1);
return SPI_I2S_ReceiveData(SPI2);
while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_BSY) == 1); Port->ODR|=S; } вот сама функция записи в массив из десяти символов (с адреса 0х00...0х09) Код void read_string() { for(i=0;i<10;i++) mass[i]=READ(i); } Пока смотрела, поняла, что после RETURN больше-то ничего не выполняется... ИСПРАВИЛА НА ТАКОЙ КОД. Код u8 READ(u16 adress) { Port->ODR&=~S;
SPI_I2S_SendData(SPI2,0b00000011); while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_BSY) == 1);
SPI_I2S_SendData(SPI2,adress); while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_BSY) == 1);
SPI_I2S_SendData(SPI2,0b00000000); while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_BSY) == 1);
err=SPI_I2S_ReceiveData(SPI2);
while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_BSY) == 1); SPI_I2S_SendData(SPI2,0b00000000); while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_BSY) == 1);
mass[i]=SPI_I2S_ReceiveData(SPI2);
while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_BSY) == 1); Port->ODR|=S; } и функцию считывания строки: Код void read_string() { for(i=0;i<10;i++) READ(i); } теперь с последним приведенным кодом каждый раз с одного и того же адреса считывает одно и тоже. Есть другие вопросы: 1) Где здесь вообще, по-вашему мнению, ошибки 2) Подключаю плату с др.такой же микросхемой памяти (но питание ниже, чем требуется), может ли из-за этого не считываться ничего с карты памяти? 3) Очень хочу что-нибудь записать в память. Но бьюсь без толку, ничего не пишет в память ни по какому адресу. Не понимаю, что именно не так. по документации WREN-> WRITE-> WRDI. ПРОСТИТЕ, что так много вопросов. Они насущные)
Сообщение отредактировал Ekka - May 17 2016, 07:42
|
|
|
|
|
May 17 2016, 07:49
|

Частый гость
 
Группа: Участник
Сообщений: 164
Регистрация: 12-04-16
Из: Белгород
Пользователь №: 91 250

|
Цитата(Obam @ May 17 2016, 07:45)  Вот без обид: datasheet на память надо прочитать хотя бы раз, но НЕ ПО ДИАГОНАЛИ (;
Далее: аргумент у SPI_I2S_SendData какого типа? Почему то байт, то "более длинный" адрес являются аргументом? У вас "spi.SPI_DataSize = SPI_DataSize_8b;" или где? Obam, спасибо, что откликнулись) Начиная со слова "Далее", подробно, немного не понимаю, о чем Вы...
|
|
|
|
|
May 17 2016, 08:14
|

Частый гость
 
Группа: Участник
Сообщений: 164
Регистрация: 12-04-16
Из: Белгород
Пользователь №: 91 250

|
но ведь принимаю я 1 байт...так?  Data out1 и Data out 2 означает что там 2 байта должно вернуться? Цитата(Ekka @ May 17 2016, 08:13)  но ведь принимаю я 1 байт...так?  Data out1 и Data out 2 означает что там 2 байта должно вернуться? не. не так.
|
|
|
|
|
May 17 2016, 09:12
|

Частый гость
 
Группа: Участник
Сообщений: 164
Регистрация: 12-04-16
Из: Белгород
Пользователь №: 91 250

|
такой нюанс "На колу мочало - начинаем сказку с начала: 1 (прописью - один) байт команды (0x3) - 1 фиктивный (безсмысленный) вычитанный байт, 2 байта адреса - 2 фиктивных вычитанных байта, 1 фиктивный байт - 1 реальный байт данных вычитанный из памяти. Всё! Разжёвано до байта (; Больше мне сказать нечего." в такой случае во всех mass[i] просто байт по адресу 0х05. А если не принимаю фиктивных байтов от команды и адреса - все работает. Obam, спасибо за терпение)
|
|
|
|
|
May 17 2016, 09:27
|

Знающий
   
Группа: Участник
Сообщений: 756
Регистрация: 14-11-14
Пользователь №: 83 663

|
Фиктивные (ладно - пусть не фиктивные. Безсмысленные! Так больше нравится?) всё равно надо забирать из DR. Я просто процитирую сам себя http://electronix.ru/forum/index.php?showt...t&p=1419227 "SPI - интерфейс синхронный и двунаправленный: синхроимпульсы мастера тактируют и данные от мастера в ведомого и одновременно данные из ведомого. На каждый переданный байт ведомому мастер получает байт от ведомого." Вот это и подразумевалось про "кол и мочало".
--------------------
Пролетарий умственного труда.
|
|
|
|
|
May 17 2016, 09:51
|

Частый гость
 
Группа: Участник
Сообщений: 164
Регистрация: 12-04-16
Из: Белгород
Пользователь №: 91 250

|
Спасибо всем, кто помогал и тратил свои нервы и знания) Все получилось) Obam, премного благодарю)  Вы были правы, Obam, единственное только, что для того, чтобы получить реальный байт потом, фиктивный не надо перед этим забирать. Просто пустую команду и забираю байт. Теперь вижу всю строку DOL32 cal ну через некоторое время увидим) может я опять накосячила...)))
Сообщение отредактировал Ekka - May 17 2016, 09:47
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|