Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: STM32 SPI
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > ARM
Alhen
Второй день пытаюсь вызвать к жизни SPI1 или 2 на STM32VLDISCOVERY.
Перерыл интернет и даташит до тошноты.
Не пойму что не так:
CODE
RCC->APB2ENR |= RCC_APB2ENR_IOPBEN; // Разрешить тактирование порта B.
RCC->APB2ENR |= RCC_APB2ENR_AFIOEN; // Тактирование альтернативных функций GPIO.
//Настройки GPIO
GPIOB->CRH |= GPIO_CRH_MODE15_1; // Выход MOSI PB.15
GPIOB->CRH &= ~GPIO_CRH_MODE15_0; // 2MHz
GPIOB->CRH &= ~GPIO_CRH_CNF15; // Push-Pull

GPIOB->CRH &= ~GPIO_CRH_MODE14; // Вход MISO PB.14
GPIOB->CRH &= ~GPIO_CRH_CNF14_0; //
GPIOB->CRH |= GPIO_CRH_CNF14_1; // Pull-Up
GPIOB->ODR |= GPIO_ODR_ODR14; //

GPIOB->CRH |= GPIO_CRH_MODE13_1; // Выход SCK PB.13
GPIOB->CRH &= ~GPIO_CRH_MODE13_0; // 2MHz
GPIOB->CRH &= ~GPIO_CRH_CNF13; // Push-Pull

GPIOB->CRH &= ~GPIO_CRH_MODE12; // Вход NSS PB.12
GPIOB->CRH &= ~GPIO_CRH_CNF12_0; //
GPIOB->CRH |= GPIO_CRH_CNF12_1; // Pull-Up
GPIOB->ODR |= GPIO_ODR_ODR12;

//Настройки SPI2
RCC->APB1ENR |= RCC_APB1ENR_SPI2EN; //Разрешаем тактирование SPI2

SPI2->CR1 &= ~SPI_CR1_SPE; //Отключаем SPI перед изменением настроек
SPI2->CR1 |= SPI_CR1_BR_0; //Задаем скорость
SPI2->CR1 |= SPI_CR1_BR_1; //
SPI2->CR1 |= SPI_CR1_CPOL; //Задаем режим
SPI2->CR1 |= SPI_CR1_CPHA; //
SPI2->CR1 &= ~SPI_CR1_DFF; //Формат данных 8 бит
SPI2->CR1 &= ~SPI_CR1_CRCEN; //Запрет CRC
SPI2->CR1 &= ~SPI_CR1_CRCNEXT; //Отключение передачи CRC
SPI2->CR1 &= ~SPI_CR1_RXONLY; //и прочих не fullduplex настроек
SPI2->CR1 &= ~SPI_CR1_SSM; //на всякий случай..
SPI2->CR1 &= ~SPI_CR1_SSI; //
SPI2->CR1 &= ~SPI_CR1_LSBFIRST; //MSB вперед
SPI2->CR1 |= SPI_CR1_MSTR; //В режиме Мастер
SPI2->CR1 &= ~SPI_CR1_BIDIMODE;//
SPI2->CR1 &= ~SPI_CR1_BIDIOE; //

SPI2->CR2 &= ~SPI_CR2_SSOE; // Запретить выход SS
// (на входе задан высокий уровень)

SPI2->CR1 |= SPI_CR1_SPE; // Включаем SPI
.....
//Пробная прием-передача
u8 temp;
while (SPI2->SR & SPI_SR_BSY);
while (!(SPI2->SR & SPI_SR_TXE));
SPI2->DR = 0x55; // Передача данных
while (SPI2->SR & SPI_SR_BSY);
while (!(SPI2->SR & SPI_SR_RXNE));
temp = SPI2->DR; // Чтение принятых данных
.......


При отладке видно, что все настройки устанавливаются как прописано в коде,
а в регистр DR данные 0x55 так и не записывается. На ногах процессора молчок.
Тоже самое делал и для SPI1 с учетом бита альтернативной распиновки.
Наверное, если взять библиотеку с функциями инициализации все бы заработало,
но хочу вот так через "stm32f10x.h".
Помогите пожалуйста разобраться.
ChipKiller
зачем же так "долбить" SPI2->CR1 ? ... все можно уместить в пару строк
Код
// включим тактирование - порт A, SPI1
  RCC->APB2ENR = RCC_APB2ENR_IOPAEN |RCC_APB2ENR_AFIOEN | RCC_APB2ENR_SPI1EN;    
  // set SPI1
  AFIO->MAPR &= 0xFFFFFFFE;     // clear AFIO_MAPR->SPI1_REMAP bit
  SPI1->CR1 = (1<<2)|(5<<3)|(1<<6)|(1<<8)|(1<<9);
  SPI1->CR2 = 0x0000;
  //  set pin
  GPIOA->BSRR = 0x00000010;     
  GPIOA->CRL   = 0xB8B34444;
Acvarif
Делал так (под новуб библиотеку периферии). Для работы с AD9832
CODE
void SPI1_Init(void)
{

// PA4 - NSS софтовый PA5 - SPI1 SCK PA7 - SPI1 MOSI

RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);

// NSS: выход push-pull
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource4, GPIO_AF_SPI1);

// SCK: выход push-pull
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource5, GPIO_AF_SPI1);

// MOSI: выход push-pull
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource7, GPIO_AF_SPI1);

SPI_InitStructure.SPI_Direction = SPI_Direction_1Line_Tx; //?
SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_128;
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_LSB;

SPI_Init(SPI1, &SPI_InitStructure);
SPI_Cmd(SPI1, ENABLE);

GPIOA->ODR |= GPIO_OTYPER_ODR_4;

}
Запускается без проблем.
Но по ходу вопрос.
Как переназначить GPIO SPI1 на другие ноги?
В новой библиотеке (в предыдущей вроде были) исчезли функции ремапинга. Куда они подевались?
Alhen
QUOTE (ChipKiller @ Jan 23 2012, 15:07) *
зачем же так "долбить" SPI2->CR1 ? ... все можно уместить в пару строк

Это от безисходности и злобы rolleyes.gif
ChipKiller
Цитата("Alhen")
Это от безисходности и злобы ...
... надеюсь все теперь все ОК ... код из рабочего примера
Цитата("Acvarif")
Как переназначить GPIO SPI1 на другие ноги?
1 - посмотреть в datasheet sm.gif .. на других ногах "висит" JTAG, так что помимо установки AFIO_MAPR->SPI1_REMAP нужно позаботиться о JTAG
Alhen
Цитата(ChipKiller @ Jan 23 2012, 20:29) *
... надеюсь все теперь все ОК ... код из рабочего примера

Благодарю за рабочий код, действительно все заработало, с меня пиво beer.gif
Я разобрался в чем была промашка, надо было назначить выходы в режиме альтернативной функции.
Код
   GPIOA->CRL   |=  GPIO_CRL_MODE7;     // Выход MOSI PA.7 (50 MHz)
   GPIOA->CRL   &= ~GPIO_CRL_CNF7_0;    // Push-Pull
   GPIOA->CRL   |=  GPIO_CRL_CNF7_1;    // с альтернативной функцией !!!!!!

Позволю себе выложить весь код тестовой программы в том же стиле.
Такой "долбеж" по регистрам неизбежен на начальном этапе освоения камня,
есть ощущение проникновения в сакральный смысл регистров biggrin.gif
CODE
#include "stm32f10x.h"
u8 temp;

void main()
{
RCC->APB2ENR |= RCC_APB2ENR_IOPAEN; // Разрешить тактирование порта A.
RCC->APB2ENR |= RCC_APB2ENR_AFIOEN; // Тактирование альтернативных функций GPIO.
GPIOA->CRL |= GPIO_CRL_MODE7; // Выход MOSI PA.7 (50 MHz)
GPIOA->CRL &= ~GPIO_CRL_CNF7_0; // Push-Pull
GPIOA->CRL |= GPIO_CRL_CNF7_1; // с альтернативной функцией !!!!!!

GPIOA->CRL &= ~GPIO_CRL_MODE6; // Вход MISO PA.6
GPIOA->CRL &= ~GPIO_CRL_CNF6_0; //
GPIOA->CRL |= GPIO_CRL_CNF6_1; // with Pull-Up

GPIOA->CRL |= GPIO_CRL_MODE5; // Выход SCK PA.5 (50 MHz)
GPIOA->CRL &= ~GPIO_CRL_CNF5_0; // Push-Pull
GPIOA->CRL |= GPIO_CRL_CNF5_1; // с альтернативной функцией !!!!

GPIOA->CRL |= GPIO_CRL_MODE4; // Выход NSS PA.4 (50 MHz)
GPIOA->CRL &= ~GPIO_CRL_CNF4; // Push-Pull General Purpose
GPIOA->BSRR = GPIO_BSRR_BS4; //

AFIO->MAPR &= ~AFIO_MAPR_SPI1_REMAP; //Сбрасываем REMAP для SPI на PA4-7
RCC->APB2ENR |= RCC_APB2ENR_SPI1EN;

SPI1->CR1 &= ~SPI_CR1_SPE; //Запрещаем SPI перед изменениями настроек
SPI1->CR1 |= SPI_CR1_BR_0; //Задаем скорость
SPI1->CR1 |= SPI_CR1_BR_1;
SPI1->CR1 |= SPI_CR1_CPOL; //Задаем режим
SPI1->CR1 |= SPI_CR1_CPHA; //
SPI1->CR1 &= ~SPI_CR1_DFF; //Формат данных 8 бит
SPI1->CR1 &= ~SPI_CR1_CRCEN; //Запрет CRC
SPI1->CR1 &= ~SPI_CR1_CRCNEXT; //Отключение передачи CRC
SPI1->CR1 &= ~SPI_CR1_RXONLY; //и прочих не fullduplex настроек
SPI1->CR1 &= ~SPI_CR1_SSM; //на всякий случай..
SPI1->CR1 &= ~SPI_CR1_SSI;
SPI1->CR1 &= ~SPI_CR1_LSBFIRST; //MSB вперед
SPI1->CR1 |= SPI_CR1_MSTR; //В режиме Мастер
SPI1->CR1 &= ~SPI_CR1_BIDIMODE;
SPI1->CR1 &= ~SPI_CR1_BIDIOE;

SPI1->CR1 |= SPI_CR1_SPE; // Включаем SPI

while(1)
{
while (SPI1->SR & SPI_SR_BSY);
while (!(SPI1->SR & SPI_SR_TXE));
SPI1->DR = 0x55; // Передача данных
while (SPI1->SR & SPI_SR_BSY);
while (!(SPI1->SR & SPI_SR_RXNE));
temp = SPI1->DR; // Чтение принятых данных
}
}


Кстати, пошагово в отладчике программа не проходит проверку на RXNE и попадает в бесконечный цикл.
Видать, где-то, RXNE успевает сброситься.
Сам кусок кода с записью и чтением я взял на форуме ST здесь
Автор утверждает, что у него код работает только в этом порядке, хотя в мануале RM0041 не рекомендуют проверять
BSY при каждой посылке и приеме.

Цитата
Note: Do not use the BSY flag to handle each data transmission or reception. It is better to use the
TXE and RXNE flags instead.
dfyz.s
Добрый вечер.
Тоже разбираюсь с SPI.

Вроде все делаю как в рабочем примере, но почему то не работает.
Припаял SPI флешку, но при отправлении данных при отладке программы в регистр ODR записывается 00FF, и так и остается.
Уже два дня мучаюсь, что может быть не так?

CODE
//////////=================SPI===============
void SPI_INIT(void)
{
SPI_InitTypeDef SPI_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;

RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC | RCC_AHB1Periph_GPIOA, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI3, ENABLE);
/* Deinitialize SPI3 peripheral */
SPI_I2S_DeInit(SPI3);

// SCK: выход push-pull PC10
GPIO_InitStructure.GPIO_Pin = PIN_EEPROM_SCK;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOC, &GPIO_InitStructure);
GPIO_PinAFConfig(GPIOC, PIN_SCK , GPIO_AF_SPI3);

// MOSI: выход push-pull PC12
GPIO_InitStructure.GPIO_Pin = PIN_EEPROM_MOSI;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOC, &GPIO_InitStructure);
GPIO_PinAFConfig(GPIOC, PIN_MOSI , GPIO_AF_SPI3);

// MISO: выход push-pull PC11
GPIO_InitStructure.GPIO_Pin = PIN_EEPROM_MISO;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOC, &GPIO_InitStructure);
GPIO_PinAFConfig(GPIOC, PIN_MISO , GPIO_AF_SPI3);

//NSS: выход push-pull - use general GPIO for CS A4
GPIO_InitStructure.GPIO_Pin = PIN_EEPROM_SPI_CS;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_Init(GPIOA, &GPIO_InitStructure);

//SPI3
SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;
SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_8;
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
SPI_Init(SPI3, &SPI_InitStructure);

SPI_Cmd(SPI3, ENABLE);
}


Отсылаю так
CODE
//////////================FOR READ_WRITE SPI=================////////////
void EEPROMSend(char byte){
SPI_I2S_SendData(SPI3, byte);
while (SPI_GetFlagStatus(SPI3, SPI_FLAG_TXE) == RESET);
}

void EEPROMSendByte(char byte){
GPIO_WriteBit(GPIOA, PIN_SPI_CS, Bit_RESET);
SPI_I2S_SendData(SPI3, byte);
while (SPI_GetFlagStatus(SPI3, SPI_FLAG_RXNE) == RESET);
GPIO_WriteBit(GPIOA, PIN_SPI_CS, Bit_SET);
}

char EEPROMReceive(){
char byte;
byte = SPI_I2S_ReceiveData(SPI3);
while (SPI_GetFlagStatus(SPI3, SPI_FLAG_RXNE) == RESET);
return byte;
}


volatile static uint8_t data=0;

int main()
{
int i= 10;
__enable_irq(); //Включаем прерывания
LedInit();
SPI_INIT();
NVIC_SetPriority(SPI3_IRQn, 2); //Устанавливаем приоритет прерываний от SPI1
NVIC_EnableIRQ(SPI3_IRQn); //Включаем прерывания от SPI1

//Write Status Register (WRSR) Instruction Sequence
i++;
EEPROMSendByte(0x06); //command for write sequence EEPROM

//for i
//Write to EEPROM
GPIO_WriteBit(GPIOA, PIN_SPI_CS, Bit_RESET);
EEPROMSend(0x02); //00000010 - write command
EEPROMSend(0x00); //address
EEPROMSend(0x00); //address
EEPROMSend(0x00); //address
EEPROMSend(0x00); //data
GPIO_WriteBit(GPIOA, PIN_SPI_CS, Bit_SET);
delay(120*5000);
///

//Read from EEPROM
GPIO_WriteBit(GPIOA, PIN_SPI_CS, Bit_RESET);
EEPROMSend(0x03); //read command
EEPROMSend(0x00); //address
EEPROMSend(0x00); //address
EEPROMSend(0x00); //address
data = EEPROMReceive(); //fake read
data = EEPROMReceive(); //read
GPIO_WriteBit(GPIOA, PIN_SPI_CS, Bit_SET);
data++;
Genadi Zawidowski
Цитата
// MISO: выход push-pull PC11

Master Input Slave Output

Оно?
dfyz.s
Обновил библиотеки - заработало MOSI, CS и SCLK
Сейчас посмотрел на осциллографе, MISO кстати и не работает. Сразу после записи команды чтения CS уходит в 1, то есть строчки
Код
    data =  EEPROMReceive();        //fake read
    data =  EEPROMReceive();        //read

Вообще пропускаются.
MISO стабильно выдает 1,7 на всем протяжении)

Может я что то не понимаю, но при отладке в строчках
Код
void SPI_I2S_SendData(SPI_TypeDef* SPIx, uint16_t Data)
{
  /* Check the parameters */
  assert_param(IS_SPI_ALL_PERIPH(SPIx));
  
  /* Write in the DR register the data to be sent */
  SPIx->DR = Data;
}


DR приравнивается 0xFE, хотя Data=0x06? smile3046.gif
Genadi Zawidowski
в приведённом коде miso программировался на вывод. Должен быть входом.
dfyz.s
На отладчик забил
Понял, в чем был косяк.

Код
uint8_t EEPROMSend(uint8_t byte){
    while (SPI_I2S_GetFlagStatus(SPI3, SPI_I2S_FLAG_TXE) == RESET);
    SPI_I2S_SendData(SPI3, byte);
  while (SPI_I2S_GetFlagStatus(SPI3, SPI_I2S_FLAG_RXNE) == RESET);
    return SPI_I2S_ReceiveData(SPI3);
    }

void EEPROMSendByte(uint8_t byte){
    GPIO_WriteBit(GPIOA, PIN_SPI_CS, Bit_RESET);
    EEPROMSend(byte);
    GPIO_WriteBit(GPIOA, PIN_SPI_CS, Bit_SET);
}

uint8_t EEPROMReceive(void)
{
  return (EEPROMSend(DUMMY_BYTE));
}


Необходимо просто отправлять байт и читать одновременно.

Но на осциле MISO все равно не работает. Что то дергается, но невысокий уровень. Может Open Drain попробовать?

Цитата
в приведённом коде miso программировался на вывод. Должен быть входом.


Код
// MISO: выход push-pull PC11
    GPIO_InitStructure.GPIO_Pin = PIN_EEPROM_MISO;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; /// Сконфигурирован как MISO. Надо как IN Сделать?
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; /// ???? или здесь Open Drain поставить?
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
    GPIO_Init(GPIOC, &GPIO_InitStructure);
Genadi Zawidowski
Нет, именно входом. А как это делается на NXP я понятия не имею... как и на STM32.
Но знаю точно, что долго искать не пришлось бы, будь я за Вашим компютером.
Impartial
Цитата(Genadi Zawidowski @ Jun 14 2012, 21:48) *
Нет, именно входом. А как это делается на NXP я понятия не имею... как и на STM32.
Но знаю точно, что долго искать не пришлось бы, будь я за Вашим компютером.


Где то так. Для SPI2.
Код
  GPIOB->CRH &= ~(GPIO_CRH_CNF15 | GPIO_CRH_MODE15);
  GPIOB->CRH |= GPIO_CRH_CNF15_1 | GPIO_CRH_MODE15; //mosi
  GPIOB->CRH &= ~(GPIO_CRH_CNF14 | GPIO_CRH_MODE14);
  GPIOB->CRH |= GPIO_CRH_CNF14_0; //miso
  GPIOB->CRH &= ~(GPIO_CRH_CNF13 | GPIO_CRH_MODE13);
  GPIOB->CRH |= GPIO_CRH_CNF13_1 | GPIO_CRH_MODE13; //sck
  GPIOB->CRH &= ~(GPIO_CRH_CNF12 | GPIO_CRH_MODE12);
  GPIOB->CRH |= GPIO_CRH_MODE12; //cs
dfyz.s
Цитата
Код
  GPIOB->CRH &= ~(GPIO_CRH_CNF15 | GPIO_CRH_MODE15);
  GPIOB->CRH |= GPIO_CRH_CNF15_1 | GPIO_CRH_MODE15; //mosi
  GPIOB->CRH &= ~(GPIO_CRH_CNF14 | GPIO_CRH_MODE14);
  GPIOB->CRH |= GPIO_CRH_CNF14_0; //miso
  GPIOB->CRH &= ~(GPIO_CRH_CNF13 | GPIO_CRH_MODE13);
  GPIOB->CRH |= GPIO_CRH_CNF13_1 | GPIO_CRH_MODE13; //sck
  GPIOB->CRH &= ~(GPIO_CRH_CNF12 | GPIO_CRH_MODE12);
  GPIOB->CRH |= GPIO_CRH_MODE12; //cs

Это для серии stm32f1xx. У меня же stm32f207.
Спасибо за советы, но у меня уже было настроено на вход как видно по моим примерам.

В итоге разобрался. Дело было в том, что ядро контроллера работает на частоте 120 МГц и порт не успевает выводить значения, которые задаешь подряд. Приходиться делать задержку.

Итоговый код программы. Может кому-то пригодиться
CODE

#include <stm32f2xx_conf.h>
#include <stdio.h>

//HSE 25 MHz
//HSI 16 MHz
// PLL configure 120 MHz signal
// PCLK1 - HSE/4 - 30 MHz(APB1); PCLK2 - HSE/2 - 60 MHz(APB2)

#define DUMMY_BYTE 0xA5
#define PIN_EEPROM_SPI_CS GPIO_Pin_4
#define PIN_TAMPER GPIO_Pin_13
#define PIN_EEPROM_MOSI GPIO_Pin_12
#define PIN_EEPROM_MISO GPIO_Pin_11
#define PIN_EEPROM_SCK GPIO_Pin_10
#define PIN_SPI_CS 0x0010
#define PIN_SCK GPIO_PinSource10
#define PIN_MISO GPIO_PinSource11
#define PIN_MOSI GPIO_PinSource12

void delay(volatile uint32_t time)
{
for (; time != 0; time --);
}

void Led_Init(void)
{
RCC -> AHB1ENR |= RCC_AHB1ENR_GPIOFEN;
GPIOF -> MODER |= GPIO_MODER_MODER6_0 |
GPIO_MODER_MODER7_0 |
GPIO_MODER_MODER8_0 ;
GPIOF -> OTYPER &= ~(GPIO_OTYPER_OT_6 |
GPIO_OTYPER_OT_7 |
GPIO_OTYPER_OT_8);
GPIOF -> OSPEEDR |= GPIO_OSPEEDER_OSPEEDR6 |
GPIO_OSPEEDER_OSPEEDR7 |
GPIO_OSPEEDER_OSPEEDR8 ;
}

//////////=================SPI===============
void SPI_INIT(void)
{
SPI_InitTypeDef SPI_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;

RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC | RCC_AHB1Periph_GPIOA, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI3, ENABLE);
/* Deinitialize SPI3 peripheral */
SPI_I2S_DeInit(SPI3);

GPIO_PinAFConfig(GPIOC, PIN_SCK , GPIO_AF_SPI3);
GPIO_PinAFConfig(GPIOC, PIN_MOSI , GPIO_AF_SPI3);
GPIO_PinAFConfig(GPIOC, PIN_MISO , GPIO_AF_SPI3);

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;

// SCK: выход push-pull PC10
GPIO_InitStructure.GPIO_Pin = PIN_EEPROM_SCK;
GPIO_Init(GPIOC, &GPIO_InitStructure);

// MISO: выход push-pull PC11
GPIO_InitStructure.GPIO_Pin = PIN_EEPROM_MISO;
GPIO_Init(GPIOC, &GPIO_InitStructure);

// MOSI: выход push-pull PC12
GPIO_InitStructure.GPIO_Pin = PIN_EEPROM_MOSI;
GPIO_Init(GPIOC, &GPIO_InitStructure);

//NSS: выход push-pull - use general GPIO for CS A4
GPIO_InitStructure.GPIO_Pin = PIN_EEPROM_SPI_CS;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_Init(GPIOA, &GPIO_InitStructure);

//SPI3
SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;
SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
SPI_Init(SPI3, &SPI_InitStructure);
SPI_Cmd(SPI3, ENABLE);
}
//////////////============================================================


//////////================FOR READ_WRITE SPI=================////////////

uint8_t EEPROM_Send(uint8_t byte){
while (SPI_I2S_GetFlagStatus(SPI3, SPI_I2S_FLAG_TXE) == RESET);
SPI_I2S_SendData(SPI3, byte);
while (SPI_I2S_GetFlagStatus(SPI3, SPI_I2S_FLAG_RXNE) == RESET);
return SPI_I2S_ReceiveData(SPI3);
}

void EEPROM_SendByte(uint8_t byte){
GPIO_WriteBit(GPIOA, PIN_SPI_CS, Bit_RESET);
EEPROM_Send(byte);
GPIO_WriteBit(GPIOA, PIN_SPI_CS, Bit_SET);
delay(2000);
}

uint8_t EEPROM_Receive(void)
{
return (EEPROM_Send(DUMMY_BYTE));
}

uint8_t EEPROM_ReadStatReg(void)
{
uint8_t byte;
GPIO_WriteBit(GPIOA, PIN_SPI_CS, Bit_RESET);
EEPROM_Send(0x05);
byte=EEPROM_Receive();
GPIO_WriteBit(GPIOA, PIN_SPI_CS, Bit_SET);
delay(2000);
return (byte);
}

void EEPROM_BulkErase(void)
{
EEPROM_SendByte(0xC7);
while(EEPROM_ReadStatReg() & 1);
}
/////=========================================================

volatile static uint8_t data=0;
volatile static uint8_t RegStat=0;

//////===================MAIN
int main()
{
__enable_irq(); //Включаем прерывания
Led_Init();
SPI_INIT();

EEPROM_BulkErase();

//Write enable (WREN) Instruction Sequence
EEPROM_SendByte(0x06); //command for write sequence EEPROM
//Write to EEPROM
GPIO_WriteBit(GPIOA, PIN_SPI_CS, Bit_RESET);
EEPROM_Send(0x02); //00000010 - write command
EEPROM_Send(0x00); //address
EEPROM_Send(0x00); //address
EEPROM_Send(0x00); //address
EEPROM_Send(0xAA); //data
EEPROM_Send(0xBB); //data
EEPROM_Send(0xCC); //data
while (SPI1->SR & SPI_SR_BSY);
GPIO_WriteBit(GPIOA, PIN_SPI_CS, Bit_SET);
delay(2000);
while (SPI1->SR & SPI_SR_BSY);
while(EEPROM_ReadStatReg() & 1);

///
GPIOF->ODR |= GPIO_OTYPER_ODR_6;

//Read from EEPROM
GPIO_WriteBit(GPIOA, PIN_SPI_CS, Bit_RESET);
EEPROM_Send(0x03); //read command
EEPROM_Send(0x00); //address
EEPROM_Send(0x00); //address
EEPROM_Send(0x00); //address
data = EEPROM_Receive(); //read
data = EEPROM_Receive(); //read
data = EEPROM_Receive(); //read
data = EEPROM_Receive(); //read
data = EEPROM_Receive(); //read
GPIO_WriteBit(GPIOA, PIN_SPI_CS, Bit_SET);
delay(2000);

///
GPIOF->ODR |= GPIO_OTYPER_ODR_8;
delay(8000000);
GPIOF->ODR &= ~GPIO_OTYPER_ODR_8;
delay(8000000);
GPIOF->ODR |= GPIO_OTYPER_ODR_8;
GPIOF->ODR &= ~GPIO_OTYPER_ODR_6;
delay(8000000);

while(1){};
}




Думал, что это как то просчитанно.
А так в общем все в проге было ОК :=)
ВитГо
хочу подключить к STM32F4 DISCOVERY дисплей LCD NOKIA 5110

использую CooCox

в софт SPI подключение проходит (так я проверил строку инициализации дисплея)

для хардварного SPI сначала вызываю инициализацию SPI2
используемые ноги:
- PB13 CLK
- PB15 MOSI
- NSS и MISO не использую так как нужно только записывать данные и SPI2 всегда в режиме мастера

Код
// Инициализация SPI2
void SPI2_Config(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    SPI_InitTypeDef  SPI_InitStructure;

    RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE);  // включили SPI2
    SPI_DeInit(SPI2); // сбрасываем настройки SPI2 на первоначальные

    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE); // включили GPIOB

    GPIO_PinAFConfig(GPIOB, GPIO_PinSource13, GPIO_AF_SPI2);   // SPI2_CLK
    GPIO_PinAFConfig(GPIOB, GPIO_PinSource15, GPIO_AF_SPI2);   // SPI2_MOSI

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_15;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStructure.GPIO_PuPd  = GPIO_PuPd_UP;
    GPIO_Init(GPIOB, &GPIO_InitStructure);

// сюда задание альтернативных функций 13 и 15 пина тоже переносил. результата нет
// GPIO_PinAFConfig(GPIOB, GPIO_PinSource13, GPIO_AF_SPI2);   // SPI2_CLK
// GPIO_PinAFConfig(GPIOB, GPIO_PinSource15, GPIO_AF_SPI2);   // SPI2_MOSI

    // SPI2
    SPI_InitStructure.SPI_Mode        = SPI_Mode_Master;
    SPI_InitStructure.SPI_Direction   = SPI_Direction_1Line_Tx;
    SPI_InitStructure.SPI_DataSize    = SPI_DataSize_8b;
    SPI_InitStructure.SPI_CPOL        = SPI_CPOL_Low;
    SPI_InitStructure.SPI_CPHA        = SPI_CPHA_1Edge;
    SPI_InitStructure.SPI_NSS               = SPI_NSS_Soft;
    SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;
    SPI_InitStructure.SPI_FirstBit          = SPI_FirstBit_MSB;
    SPI_Init(SPI2, &SPI_InitStructure);

    SPI_Cmd(SPI2, ENABLE);
}

частота камня 168 мгц поэтому взял максимальный делитель для SPI2 = 256


далее инициализирую GPIO для других линий дисплея
Код
// Инициализация LCD NOKIA 5110 c помощью SPI2
void lcd5110_init(void) {
    GPIO_InitTypeDef GPIO_InitStructure;
    unsigned char y, x;

//    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE); // такт GPIOB, для софт SPI, для хард - делается при ините SPI2

// конфигурируем пины порта B как выход
// для soft spi
//    GPIO_InitStructure.GPIO_Pin  =GPIO_Pin_10 | GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;

// для хардварного SPI
    GPIO_InitStructure.GPIO_Pin  =GPIO_Pin_10 | GPIO_Pin_14;

// общие строки инициализации
    GPIO_InitStructure.GPIO_Mode =GPIO_Mode_OUT;
    GPIO_InitStructure.GPIO_OType=GPIO_OType_PP;
    GPIO_InitStructure.GPIO_PuPd =GPIO_PuPd_UP;
    GPIO_InitStructure.GPIO_Speed=GPIO_Speed_100MHz;
    GPIO_Init(GPIOB, &GPIO_InitStructure);


далее работаю с дисплеем, этот код используется и в софт и хард работе SPI c дисплеем
Код
    // Линии управления LCD в неактивное состояние
    LCD_CS1;            // CS=1
    LCD_RST1;           // RST=1
    delay_ms(10);      // пауза 0.2 сек.

    // сброс дисплея
    LCD_CS0;            // CS=0
    LCD_RST0;           // RST=0
    delay_ms(10);      // пауза 0.2 сек.
    LCD_RST1;           // RST=1
    LCD_CS1;            // CS=1
    delay_ms(10);      // пауза 0.2 сек.

    // последовательность инициализации дисплея
    LCD_DC0;            // передача команды
    LCD_SendData(0x21);
    LCD_SendData(0xC6);
    LCD_SendData(0x06);
    LCD_SendData(0x13);
    LCD_SendData(0x20);
    LCD_SendData(0x0C);

    LCD_DC0;            // передача команд
    LCD_SendData(0x40);
    LCD_SendData(0x80);

    LCD_DC1;            // передача данных
    for (y=0;y<6;y++) for (x=0;x<84;x++) LCD_SendData(0x88);

    LCD_DC0;            // передача команд
    LCD_SendData(0x0C);
}


и собственно, сама процедура передачи данных на дисплей
Код
void LCD_SendData(unsigned char data) {
//    unsigned char i;  // для программного SPI

    LCD_CS0;            // включаем выбор дисплея
// хардварный SPI
    SPI_I2S_SendData(SPI2, data);
    while(SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE) == RESET);


/*   // это реализация программного SPI работает!
       // программный SPI
    for(i=0;i<8;i++)
    {
        if (data & 0x80) LCD_MOSI1; else LCD_MOSI0;
        data = data<<1;
        LCD_SCK0;
        LCD_SCK0;
        LCD_SCK0;
        LCD_SCK1;
        LCD_SCK1;
        LCD_SCK1;
    }
*/
    LCD_CS1;
}


процедуры вызываю из main()
Код
   SPI2_Config(); // конфигурация SPI2

    lcd5110_init(); // конфигурация LCD


почему не работает аппаратный SPI2?
HHIMERA
Цитата(ВитГо @ Oct 21 2012, 09:14) *
и собственно, сама процедура передачи данных на дисплей


Каким боком здесь SPI_I2S_FLAG_TXE ???
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.