Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Память M95-256
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > Все остальные микроконтроллеры
Ekka
Ребята, доброго времени суток) Бьюсь над памятью М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);
}

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



Добавила. Но что-то не помогло. Где-то в другом косяк...
Ekka
Могут ли быть мною опущены какие-то временные задержки? Возвращает то 5, то 255....
AHTOXA
Вы вообще неправильно работаете с 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;
}

Ekka
Хм... ща попробуем

Спасибо Вам за ответы)))

Вот думаю... может я неправильно подключила.... У меня память М95-256. Есть у нее вход-Q, выход - D, выбор чипа S, С- тактирование. согласно с принципами SPI, MOSI соединяю c Q, MISO - c D, CS - S, NSS - C... HOLD и W - настраиваю как выходы, кидаю на свободные пины.

Хм.... почему же на MISO мк висит единица, просто единица... 255 гонит и все тут. Хотя команда проходит
AHTOXA
Цитата(Ekka @ Apr 13 2016, 16:28) *
Хм.... почему же на MISO мк висит единица, просто единица... 255 гонит и все тут. Хотя команда проходит

Потому что вы её настроили как выход (GPIO_Mode_Out_PP). Настройте как вход.
Ekka
А так можно написать?

#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);
}
AHTOXA
Цитата(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;
}


ЗЫ. Для оформления кода пользуйтесь кнопкой код:
Ekka
если я убираю это. Цикл WHILE , который ждет, пока установится флаг RXNE виснет.
Код
SPI_I2S_ITConfig(SPI1, SPI_I2S_IT_RXNE, ENABLE);

Немного не поняла...зачем отправлять ВТОРОЙ байт? Я же отправляю команду - СЧИТАТЬ РЕГИСТР. Разве не должен сразу приходить ответный байт? Что означает второй байт? О_О

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

Теперь микросхема отвечает просто нулем. Не могу понять, в документации вроде все так просто. Выбираем чип, отправляем команду считать регистр, сбрасываем чип, считываем ответ. crying.gif
AHTOXA
Цитата(Ekka @ Apr 13 2016, 17:46) *
если я убираю это. Цикл WHILE , который ждет, пока установится флаг RXNE виснет.

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

Ну вы же сами вот пишете:
Цитата(Ekka @ Apr 13 2016, 17:46) *
в документации вроде все так просто. Выбираем чип, отправляем команду считать регистр, сбрасываем чип, считываем ответ. crying.gif

Видите, сначала надо отправить команду, и только потом считать ответ. Поскольку контроллер является мастером, для считывания ответа он должен выдавать тактирование (CLK). А для этого надо записать что-то в регистр данных. Вот и появляется второй байт.
Цитата(Ekka @ Apr 13 2016, 17:46) *
и еще вопрос. Почему чип сбрасываем только после того, как примем ответ? Разве выбор чипа не сбрасывают после завершения каждой команды? Или мы его сбрасываем только после окончания вообще работы с микросхемой памяти?

Тут я не могу сказать, я не знаю, что у вас за память. Делайте, как написано в документации.
Ekka
Спасибо за Ваши ответы))) Микросхема начала отвечать. Присылает байт статуса. НО. Не могу его правильно считать. При установке ожидания флага (цикл 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;
}


функция просто постоянно крутится в вечном цикле в мэине

Obam
Цитата(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.
Ekka
Цитата(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... чет я запуталась вкорень


Может, она того.... сгорела sad.gif

Может, я неправильно W и HOLD настроила? Они же должны быть в единицах? Если HOLD опущу - будет пауза. Если W опущу, установлю защиту от записи. Или я опять что-то путаю.


Может, кто делал такую штуку и есть хоть похожий пример?
Obam
Кодом в меня тыкать не надо (:

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

Смысл моего замечания таков: физически MOSI разведён на Q? физически MISO разведён на D? Если так, то хоть обпереопределяйся - лажа не исправится.


Нет... у меня физически MISO разведен на Q, а MOSI - на D.

подключено вроде все правильно...уже несколько раз перепроверено(
Obam
Хорошо, едем дальше…

В п/п вам надо 2 раза знать статус памяти?
"void RDSR()
{
Port->ODR&=~S;
SPI_I2S_SendData(SPI1,0b00000101);

// где ожидание окончания передачи/приёма и вычитка DR? При этом здесь не будет действительных данных от памяти.

SPI_I2S_SendData(SPI1,0b00000000);
// где ожидание окончания передачи/приёма и вычитка DR? А здесь данные будут.

SPI_I2S_SendData(SPI1,0b00000000);
// где ожидание окончания передачи/приёма и вычитка DR? И здесь будут.
// while((SPI_I2S_GetITStatus(SPI1,SPI_I2S_IT_RXNE)==0));
answer=SPI_I2S_ReceiveData(SPI1);
Port->ODR|=S;
}
"
SPI - интерфейс синхронный и двунаправленный: синхроимпульсы мастера тактируют и данные от мастера в ведомого и одновременно данные из ведомого. На каждый переданный байт ведомому мастер получает байт от ведомого.



Ekka
Спасибо за разъяснение, 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);//считываем байт
Obam
Цитата(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 видели?
Ekka
Да. Но с пониманием туго( smile3046.gif
Obam
Цитата(Ekka @ Apr 14 2016, 15:14) *
Да. Но с пониманием туго( smile3046.gif


Так приложите к ней рисунок со стр. 19 из CD00103810.pdf: SCK это C, MOSI это D, MISO это Q.

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

Байт положили в DR, он автоматом переносится в сдвиговый регистр и начинает побитно отправляться ведомому;
при этом ведомый побитно отдаёт свой байт ведущему. Все биты переданы (а соответственно и приняты) - тогда
выставляется флаг RXNE => можно считать полученное.



Только чур камнями не бросать)
Тогда выходит
сначала я кладу в DR регистр мою команду,
потом жду пока TXE флаг установится,
потом передаю пустой байт,
потом жду пока RXNE флаг установится,
и забираю ответный байт?
Obam
Цитата(Ekka @ Apr 14 2016, 16:42) *
Только чур камнями не бросать)
Тогда выходит
сначала я кладу в DR регистр мою команду,
потом жду пока TXE флаг установится,
потом передаю пустой байт,
потом жду пока RXNE флаг установится,
и забираю ответный байт?


Не надо TXE сейчас использовать.

Ваши действия таковы:
"сначала я кладу в DR регистр мою команду,
потом жду пока RXNE флаг установится,
забираю фиктивный ответный байт
потом передаю пустой байт,
потом жду пока RXNE флаг установится,
и забираю ответный байт?
"

В посте #19 уже и код был приведён.
Ekka
Нет... что-то не так. Микросхема не отвечает. Хотя байты передаются. Микросхему проверили, протестили, рабочая, с др.устройством все прекрасно отвечает... хмм

Почему TXE сейчас не используем?
Obam
Цитата(Ekka @ Apr 14 2016, 17:05) *
Нет... что-то не так. Микросхема не отвечает. Хотя байты передаются. Микросхему проверили, протестили, рабочая, с др.устройством все прекрасно отвечает... хмм


С каким "др.устройством все прекрасно отвечает"? Телепаты в отпуске (;

Цитата
Почему TXE сейчас не используем?


ТXE - это флаг пустого DR, но не пустого сдвигового регистра; используется для того чтобы повысить пропускную способность SPI. На рис. 225 всё "до тла" разжёвано.
Ekka
Такая штука... как только я использую ожидание флага RXNE, просто добавляю эти строки... на входе схемы памяти перестает отображаться та команда, которую она получает от МК и просто висит единица... почему так??? (((
что за магия..
Obam
Не нервничайте, спокойно читайте datasheet и RefMan; JTAG и осциллограф у вас, надеюсь, есть; проверяйте содержимое регистров.
Всё, что нужно было, всё было обсуждено.

Ждем положительного результата.
Ekka
Код
#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);
}


почему-то так все работает....


спасибо всем за подсказки, ребята)) и за доходчивые и конкретные объяснения) wink.gif
Ekka
возник др.вопрос. Чтобы считать что-нибудь из памяти по адресу например, 0хА1, нужно:
выбрать чип
в регистр DR SPI-я положить команду
считать фиктивный байт
отправить адрес
считать фиктивный байт
отправить пустую команду
считать реальный ответ
сбрасывать чип не надо

ТАК? или при передаче адреса не надо фиктивный байты считывать?


и еще: как мне принять только один байт? и чтобы больше не принимать значений... по одному конкретному адресу может лежать только один байт?
Ekka
Вроде разобралась как принять байт из памяти. Начальный алгоритм был неправильный. Возник др.вопрос. Есть какая-то особенность записи байта в память. Не пойму, ЧТО именно пытаются сказать в документации.
Ekka
Ребята, снова стучу в эту тему((( Недавно обнаружила, что 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. ПРОСТИТЕ, что так много вопросов. Они насущные)
Obam
Вот без обид: datasheet на память надо прочитать хотя бы раз, но НЕ ПО ДИАГОНАЛИ (;

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

Далее: аргумент у SPI_I2S_SendData какого типа? Почему то байт, то "более длинный" адрес являются аргументом? У вас "spi.SPI_DataSize = SPI_DataSize_8b;" или где?


Obam, спасибо, что откликнулись) Начиная со слова "Далее", подробно, немного не понимаю, о чем Вы...
Obam
Всё ж пояснил; в свой код гляньте: ф-ия READ и далее аргументы у SPI_I2S_SendData
Ekka
Так... у меня получается... SPI настроен на 8 бит. Команда имеет тот же формат. А вот адрес... он же как 16 бит передается... так что ли... у меня тогда что.. адрес неверно передается... пожалуйста, помидорами не кидайте( crying.gif

а тип у 2-го аргумента SPI_I2S_SendData() uint16_t...
Obam
Адрес в память в два приёма должен выдаваться.
Ekka
вот же ж... попробуем sad.gif
Obam
Вы бы взяли рисуночек со стр.23 datasheet-а и отметили чему каждый вызов соответстсвует, вот, глядишь, просветление и наступит (:
Ekka
но ведь принимаю я 1 байт...так? crying.gif

Data out1 и Data out 2 означает что там 2 байта должно вернуться?

Цитата(Ekka @ May 17 2016, 08:13) *
но ведь принимаю я 1 байт...так? crying.gif

Data out1 и Data out 2 означает что там 2 байта должно вернуться?

не. не так.
Obam
На колу мочало - начинаем сказку с начала:
1 (прописью - один) байт команды (0x3) - 1 фиктивный (безсмысленный) вычитанный байт,
2 байта адреса - 2 фиктивных вычитанных байта,
1 фиктивный байт - 1 реальный байт данных вычитанный из памяти. Всё! Разжёвано до байта (; Больше мне сказать нечего.
Ekka
УРА)) УРА) УРА) надеюсб, не зря радуюсь хоть.... СПА_СИ_БО, OBAM))) А почему SPI возвращает значения так: на 2 запрос, приходит ответ с первого запроса. Т.е. в массиве у меня значение с адреса 0х01 лежит под номером mass[0], c адреса 0х02 в mass[1]. Как же мне тогда самое первое значение увидеть???

считанная строка совпадает с той, которая програмкой считывает при проверке) записывает наконец-то в память) Но вот как мне самое первое значение получить..? по проверке строка начинается с DOL32... но я вижу только OL32
Obam
Вот здесь самое время остановиться и начать штудировать документацию.
Fig.225 на стр.524 в cd00246267.pdf
Ekka
такой нюанс
"На колу мочало - начинаем сказку с начала:
1 (прописью - один) байт команды (0x3) - 1 фиктивный (безсмысленный) вычитанный байт,
2 байта адреса - 2 фиктивных вычитанных байта,
1 фиктивный байт - 1 реальный байт данных вычитанный из памяти. Всё! Разжёвано до байта (; Больше мне сказать нечего."

в такой случае во всех mass[i] просто байт по адресу 0х05. А если не принимаю фиктивных байтов от команды и адреса - все работает.

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

Вы были правы, Obam, единственное только, что для того, чтобы получить реальный байт потом, фиктивный не надо перед этим забирать. Просто пустую команду и забираю байт. Теперь вижу всю строку DOL32 cal

ну через некоторое время увидим) может я опять накосячила...)))
Obam
Цитата(Ekka @ May 17 2016, 13:51) *
Все получилось)


sm.gif Как говорится:"Беги за красненьким…"
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.