Jump to content

    
Sign in to follow this  
sgrig

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

Recommended Posts

Пытаюсь подключить 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;

}

Share this post


Link to post
Share on other sites

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

SPI_InitStructure.SPI_NSS = SPI_NSS_Hard;

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

Share this post


Link to post
Share on other sites
Возможно, причина в том, что управлении линией ChipSelect происходит аппаратно, т.е. дергается на каждом байте.

SPI_InitStructure.SPI_NSS = SPI_NSS_Hard;

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

 

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

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

Share this post


Link to post
Share on other sites
/* 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), и будет вам счастье.

Share this post


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

 

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

Share this post


Link to post
Share on other sites

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

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

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

Share this post


Link to post
Share on other sites

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

Share this post


Link to post
Share on other sites

Вы абсолютно правы, этот момент я упустил. Но беда в том, что все осталось на месте, хотя в процедуру инициализации 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);

Share this post


Link to post
Share on other sites

Победил так: цикл обращения к 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, что противоречит документации. А все работает!

Share this post


Link to post
Share on other sites

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

 

\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 пробовал делать предварительную проверку приёмного буффера - ничего не меняет. Уже второй день бьюсь :( .

Share this post


Link to post
Share on other sites

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

 

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

Edited by baralgin

Share this post


Link to post
Share on other sites

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

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Sign in to follow this