Перейти к содержанию
    

STM32F103 и его SPI - непонятки

Пытаюсь подключить AD7793 к STM32F103 через SPI. В регистры АЦП все пишется без проблем, но читается из них что попало. Самое удивительное, что AD7793 выдает то, что надо - смотрю осциллоскопом на MISO процессора. Может, кто сталкивался? А то уже крыша едет... Буду признателен за любые идеи.

 

Инициализация такая:

void init_spi(void)

{

GPIO_InitTypeDef GPIO_InitStructure;

SPI_InitTypeDef SPI_InitStructure;

/* GPIOA, GPIOB and SPI1 clock enable */

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_SPI1, ENABLE);

/* Configure SPI1 pins: NSS, SCK, MISO and MOSI ----------------------------*/

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;

GPIO_Init(GPIOA, &GPIO_InitStructure);

/* SPI1 configuration ------------------------------------------------------*/

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_High;

SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;

SPI_InitStructure.SPI_NSS = SPI_NSS_Hard;

SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_32;

SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;

SPI_InitStructure.SPI_CRCPolynomial = 7;

SPI_Init(SPI1, &SPI_InitStructure);

/* Enable SPI1 NSS output for master mode */

SPI_SSOutputCmd(SPI1, ENABLE);

/* Enable SPI1 */

SPI_Cmd(SPI1, ENABLE);

}

 

8-ми битные регистры читаю так:

char AD7793_read(char Reg)

{

 

char result;

char reg = ((Reg&7)<<3) | 0x40;

 

/* write to Communication Register AD7793 */

while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);

SPI_I2S_SendData(SPI1, reg);

 

/* read byte with dummy write */

while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);

SPI_I2S_SendData(SPI1, 0x00);

while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET);

result = SPI_I2S_ReceiveData(SPI1);

 

return result;

}

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

SPI_InitStructure.SPI_NSS = SPI_NSS_Hard;

Попробуйте программно дергать этим выводом согласно даташита на АЦП.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

SPI_InitStructure.SPI_NSS = SPI_NSS_Hard;

Попробуйте программно дергать этим выводом согласно даташита на АЦП.

 

1) Линия не дергается - стоит в нуле.

2) АЦП выдает то, что нужно (см. пост выше).

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

/* Configure SPI1 pins: NSS, SCK, MISO and MOSI ----------------------------*/
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  GPIO_Init(GPIOA, &GPIO_InitStructure);

 

Так вы все ноги на выход настроили. Включите MISO на вход (Input Floating или Input Pulled), и будет вам счастье.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Так вы все ноги на выход настроили. Включите MISO на вход (Input Floating или Input Pulled), и будет вам счастье.

 

Почему? С чего вы взяли? Здесь все ноги настроены на альтернативные функции, насколько я понимаю.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Из своего собственного опыта.

GPIO_Mode_AF_PP - Альтернативный режим, Пушпульный Выход. А MISO должен быть настроен как вход.

Специального альтернативного режима на вход нет, поэтому используйте GPIO_Mode_IN_FLOATING, GPIO_Mode_IPU или GPIO_Mode_IPD - на свой вкус.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

В юзермануале есть для этого даже раздел специальный есть "8.1.11 Peripherals’ GPIO configurations", где все настройки портов для периферии расписаны

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Вы абсолютно правы, этот момент я упустил. Но беда в том, что все осталось на месте, хотя в процедуру инициализации GPIO внес изменения:

 

/* Configure SPI1 pins: NSS, SCK and MOSI as alternate functions -----------*/

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_7;

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;

GPIO_Init(GPIOA, &GPIO_InitStructure);

/* Configure SPI1 pin: MISO as pull-up input -------------------------------*/

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_UPD;

GPIO_Init(GPIOA, &GPIO_InitStructure);

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Тогда остаётся перебрать другие комбинации CPOL и CPHA, понизить скорость, и таки попробовать поуправлять NSS вручную.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Победил так: цикл обращения к SPI вынес в отдельную функцию, в которой первым делом чищу приемный буфер:

 

u8 send_spi(u8 byte)

{

/* Flush away any rogue data in rx buffer */

if (SPI_I2S_GetFlagStatus(AD7793_SPI, SPI_I2S_FLAG_RXNE) == SET) SPI_I2S_ReceiveData(AD7793_SPI);

 

/* Loop while DR register in not empty */

while(SPI_I2S_GetFlagStatus(AD7793_SPI, SPI_I2S_FLAG_TXE) == RESET);

 

/* Send byte through the AD7793_SPI peripheral */

SPI_I2S_SendData(AD7793_SPI, byte);

 

/* Wait to receive a byte */

while(SPI_I2S_GetFlagStatus(AD7793_SPI, SPI_I2S_FLAG_RXNE) == RESET);

 

/* Return the byte read from the SPI bus */

return SPI_I2S_ReceiveData(AD7793_SPI);

}

 

Все заработало как часы. Самое смешное, что вернул MISO в состояние GPIO_Mode_AF_PP, что противоречит документации. А все работает!

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

В исходниках этой папки:

 

\STM32F10x_StdPeriph_Lib_V3.1.2\Project\STM32F10x_StdPeriph_Examples\SPI\M25P64_FLASH

 

SCK, MISO и MOSI - настроены как GPIO_Mode_AF_PP.

 

...

 

Не могу связать stm32 с FM25L04. Пациент практически живёт, но что-то не так. В общем статусный регистр нормально читается и пишется (там фактически два бита защиты только). Но вот заставить писать и читать нормально ячейки памяти не могу. Тайминги просматриваю логическим анализатором. При записи ничего криминального нет и всё проходит в соответствии с диаграммами даташита на FM25. А вот чтение работает не верно: на линии MISO просто повторяется DUMMY-байт и при этом чтение SPI_I2S_ReceiveData возвращает 0.

 

Настройка MISO на плавающий вход ничего не меняет. CS управляется программно (отрабатывает адекватно).

 

Вот кусок кода:

 

void spi_init(void)
{
SPI_FLASH_CS_HIGH();
SPI_InitTypeDef   SPI_InitStructure;

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_16;
SPI_InitStructure.SPI_FirstBit			= SPI_FirstBit_MSB;
SPI_InitStructure.SPI_CRCPolynomial 	= 7; /* ïî õîäó íå íóæåí */

SPI_Init(SPI_FM25, &SPI_InitStructure);
}



static uint8_t sendByte(uint8_t byte)
{
WAIT_TXE();
SPI_I2S_SendData( SPI_FM25, byte );
WAIT_RXNE();
return SPI_I2S_ReceiveData(SPI_FM25);
}




void spi_readBuf(uint16_t addr, uint8_t* buff, uint16_t buff_size)
{
uint_fast16_t i;
if( 
		( addr > FM25_MAX_ADDR )
	||	( buff_size > FM25_MAX_ADDR )
	||	( !buff ) 
) return;

SPI_FLASH_CS_LOW();
{
	sendByte(FM25_READ_ADDR_HI( addr ));		
	sendByte(FM25_READ_ADDR_LO( addr ));		
	for( i = 0; i < buff_size; i++ )
	{
		buff[i] = sendByte(FM25_CMD_DUMMY);
	}
}
SPI_FLASH_CS_HIGH();
}

void spi_writeBuf(uint16_t addr, uint8_t* buff, uint16_t buff_size)
{
uint_fast16_t i;
if( 
		( addr > FM25_MAX_ADDR )
	||	( buff_size > FM25_MAX_ADDR )
	||	( !buff ) 
) return;

SPI_FLASH_WriteEnable();

SPI_FLASH_CS_LOW();
{
	sendByte( FM25_WRITE_ADDR_HI( addr ) );
	sendByte( FM25_WRITE_ADDR_LO( addr ) );
	for( i = 0; i < buff_size; i++ )
	{
		sendByte(buff[i]);
	}
}
SPI_FLASH_CS_HIGH();
}

void spi_test(void)
{
static uint8_t buff[1];
buff[0] = 0x22;

spi_writeBuf(0x0000, buff, 1 );

spi_readBuf(0x0000, buff, 1);
}

 

Функции FM25_READ_ADDR_HI/LO и FM25_WRITE_ADDR_HI/LO - дают нужный опкод на чтение и запись + нужный адрес. Работают корректно. В функции sendByte пробовал делать предварительную проверку приёмного буффера - ничего не меняет. Уже второй день бьюсь :( .

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Модифицировал функцию чтения до непрерывности:

 

static uint8_t readOneByte(uint16_t addr)
{
    uint8_t ret;
    SPI_FLASH_CS_LOW();
        WAIT_TXE();        SPI_I2S_SendData(SPI_FM25, FM25_READ_ADDR_HI( addr ));
        WAIT_TXE();        SPI_I2S_SendData(SPI_FM25, FM25_READ_ADDR_LO( addr ));
        WAIT_RXNE();    SPI_I2S_ReceiveData(SPI_FM25);
        WAIT_TXE();        SPI_I2S_SendData(SPI_FM25, FM25_CMD_DUMMY );
        WAIT_RXNE();    SPI_I2S_ReceiveData(SPI_FM25);
        WAIT_RXNE();    
                ret =     SPI_I2S_ReceiveData(SPI_FM25);
    SPI_FLASH_CS_HIGH();    
    return ret;
}

 

Шесть последовательных вызовов с адресом от 0 до 5. Все вызовы возвращают 0. При этом, что происходит на выводах в приложенной картинке(всё как в даташите..). На ней снизу вверх: CS, SCK, MOSI, MISO . DUMMY равен 0x71. На MISO иногда проскакивают значения но они не ловятся приёмником...

 

ps: картинка gif - нужно кликнуть.

post-42680-1260455682_thumb.png

Изменено пользователем baralgin

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Отбой... впаяли более плотную микросхему, в которой адрес двухбайтный, вследствии чего она ничего не передавала после первого байта адреса... Удосужиться прочитать реальную маркировку пришло в голову только на третий день мучений :) .

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

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

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...