2017-02-14 8 views
2

데이터를 수신하지 않습니다. 나는 간단한 루프 백 시스템 시작 : 나는 TXFIFOLVL 상태를 확인하고는 전체가 아닌 경우 나는 다시 내 RxBuffer에 (내가 DR 에서 데이터를 읽을 다음해야 루프 DR 레지스터, 내 데이터를 전송RXFIFOLVL은 비어 있지 않습니다.)하지만 문제가 발생했습니다. 수신 버퍼에서 아무 것도 얻지 못하고 이유를 알 수없는 것 같습니다. 내가 에게 HAL 또는 표준 주변 장치 라이브러리를 사용하지 않는, 그래서 나는 SPI 구성하고이 같은 레지스터 값을 통해 사용 :STM32 디스커버리 F3 SPI 루프백 RXFIFO 내가 <em>STM32 F3 디스커버리</em> 키트와 함께 일하고 주변 <em>SPI</em> 덤비는 시작했다

헤더 파일 에 대한 SPI 코드 :

#define GPIOA_ENABLE     0b1<<17    // Enable GPIO port A clock in AHBENR register 
#define SPI1_CLOCK_ENABLE    0b1<<12    // Enable SPI1 clock in APB2ENR register 
#define SPI1_PIN_ALT_FNC    0b1010<<4   // Sets PA5,PA6 & PA7 to Alternative function 
#define SPI1_OUTPUT_TYPE    ~(0b111<<5)   // Sets PA5, PA6 & PA7 to push-pull 
#define SPI1_PIN_SPEED     0b1111<<4   // Sets pins from 4 to 7 to work on 50 MHz output speed 
#define SPI1_PIN_ALT_FNC_LOW   0b0101<<4   // Sets the Alternative function to AF5 in alternative function low register 
#define SPI1_PIN_ALT_FNC_HIGH   0b0101<<4   // Sets the Alternative function to AF5 in alternative function high register 
#define SPI1_BAUDRATE_PRESCALER_2  0b000<<3   // F_PCLK/2 
#define SPI1_BAUDRATE_PRESCALER_128  0b110<<3   // F_PCLK/128 
#define SPI1_MASTER_MODE    0b1<<2    // Sets the SPI1 to master mode 
#define SPI1_PERI_ENABLE    0b1<<6    // Enable the SPI peripheral 
#define SPI1_SSM_ENABLE     0b1<<9    // Enable SPI software slave management 
#define SPI1_SSI_ENABLE     0b1<<8    // SPI1 internal slave select 
#define SPI1_NSSP_ENABLE    0b1<<3    // Enable NSS pulse management 
#define SPI1_FRXTH_8BIT     0b1<<12    //Set the FIFO reception threshold to 8 bits 
#define SPI1_DATA_SIZE     0b0111<<8   // SPI1 DATA size 
#define SPI1_TXFIFO_FULL_FLAG   0b11<<11   // SPI1 Tx FIFO transmission flag 
#define SPI1_RXFIFO_EMPTY_FLAG   0b00<<9    // SPI1 Rx FIFO reception flag 

#include "main.h" 
#include "stm32f3xx_hal.h" 

void spi_init(); 
void spi_WriteRead(uint8_t *rxBuffer, uint8_t *txBuffer, uint8_t bufferSize); 

코드 파일 에 대한 SPI 코드 :

#include "SPI_toSD.h" 

/* SPI1 configuration 
* PA5 - SCK 
* PA6 - MISO 
* PA7 - MOSI 
*/ 
void spi_init(){ 

// Start the GPIO and peripheral clocks in Reset and Clock Control register 
RCC->AHBENR |= GPIOA_ENABLE; 
RCC->APB2ENR |= SPI1_CLOCK_ENABLE; 

// Configure the GPIOs for SPI communication 
GPIOA->MODER |= SPI1_PIN_ALT_FNC; 
GPIOA->OTYPER &= SPI1_OUTPUT_TYPE; 
GPIOA->OSPEEDR |= SPI1_PIN_SPEED; 
GPIOA->AFR[0] |= SPI1_PIN_ALT_FNC_LOW; 
GPIOA->AFR[1] |= SPI1_PIN_ALT_FNC_HIGH; 

// Configure the SPI peripheral 
SPI1->CR1 |= SPI1_BAUDRATE_PRESCALER_2; 
SPI1->CR1 |= SPI1_SSM_ENABLE; 
SPI1->CR1 |= SPI1_MASTER_MODE; 
SPI1->CR1 |= SPI1_SSI_ENABLE; 
SPI1->CR2 |= SPI1_DATA_SIZE; 
SPI1->CR2 |= SPI1_FRXTH_8BIT; 
SPI1->CR2 |= SPI1_NSSP_ENABLE; 
SPI1->CR1 |= SPI1_PERI_ENABLE; 
SPI1->CR1 &= ~SPI1_SSI_ENABLE; 

} 

void spi_WriteRead(uint8_t *rxBuffer, uint8_t *txBuffer, uint8_t bufferSize){ 
int i; 
while((SPI1->SR & 0b11<<11)==SPI1_TXFIFO_FULL_FLAG); 
for(i=0;i<bufferSize;i++){ 
     SPI1->DR |= *txBuffer; // send *txBuffer++ 
     txBuffer++; 


    while((SPI1->SR & 0b11<<9)!=SPI1_RXFIFO_EMPTY_FLAG){ 
     *rxBuffer = SPI1->DR; 
     rxBuffer++; 
    } 
} 

} 

주에서 나는 단순히 내 버퍼를 정의하고이처럼 초기화 : 내 spi_WriteRead가() 함수는 나는이 버퍼는 같은 값을 가질 것으로 예상이라고 그래서 자연스럽게 후

uint8_t rx_buff[SIZE] = {0,0,0,0,0,0,0,0,0,0}; 
uint8_t tx_buff[SIZE] = {1,2,3,4,5,6,7,8,9,10}; 

.

내 spi_init() 함수를 호출하고 내 while 루프에서 나는() 함수 spi_WriteRead를 호출

#define SIZE 10 

내가 를 사용

spi_WriteRead(rx_buff,tx_buff,SIZE); 

크기가 나의은 main.c에 정의되어 있습니다 SW4STM32 코드 및 디버깅 환경에서 내 디버거에서 모든 레지스터 값을 볼 수 있습니다. 내 SPI은 내가 정의한대로 초기화되고 데이터가 TXFIFO 버퍼로 전송되지만 아무 것도 RXFIFO 버퍼로 전송되지 않습니다. 내가 SPISR 등록을 선택하면 내 TXFIFO가 가득 볼 수 있지만, RXFIFO 플래그는 비어 있음을 말한다.

내가 뭘 잘못하고 있는지 알 수있는 사람이 있습니까? 내가 심하게 오해하는 무엇인가 간단한 약 SPI? 귀하의 의견을 보내 주셔서 감사합니다!

+0

오실로스코프/로직 분석기로 SPI의 물리적 라인을 검증 했습니까? –

+1

그래, 방금 피코 스코프 (PicoScope)로 확인해 봤는데, ** RXFIFO **가 비어있는 동안 ** TXFIFO **가 가득 차고 머무르는 것을 설명하는 횡설수설을 보내는 것처럼 보인다. – saukijan

+0

좋은 라이브러리를 사용하지 않을 이유가 있다면? 어쨌든, Keil https://www.keil.com/dd2/pack/의 매우 편리한 io 드라이버가 있습니다. –

답변

2

편집 :

여기 잘보세요 : #define 매크로는 일반적으로 좋은 생각으로 간주하는 이유

#define SPI1_SSI_ENABLE     0b1<<8 
... 
SPI1->CR1 |= SPI1_PERI_ENABLE; 
SPI1->CR1 &= ~SPI1_SSI_ENABLE; 

지금 당신은 아마 알 수 있습니다. 연산이있는 모든 값에 괄호가 있으므로 stm32f3xxx.h 헤더의 #define 값을 사용하면이 문제가 발생하지 않습니다. 너는 그들을 가지고 있지 않다.코드가 컴파일러에 대해 다음과 같습니다 이유 :

SPI1->CR1 |= SPI1_PERI_ENABLE; 
SPI1->CR1 &= (~0b1)<<8; 

그리고 더 진행 :에 해당

SPI1->CR1 |= SPI1_PERI_ENABLE; 
SPI1->CR1 &= ~0b1<<8; 

SPI1->CR1 |= SPI1_PERI_ENABLE; 
SPI1->CR1 &= 0xffffff00; 

을 아마 없을 당신이 원하는 무엇을.

또한 장치가 마스터 인 경우 SSI 및 SSM 비트를 모두 설정해야합니다. ORIGINAL https://stackoverflow.com/a/42169600/157344

:

이 주를 수행, 이들 장치에서 당신이 SPI1->DR 액세스 직접 보내기/한 번에 2 바이트를받을 수 있습니다. 이 레지스터는 uint16_t으로 정의되고 SPI는 "데이터 패킹"(참조 설명서에서 검색)을 지원하기 때문입니다. 당신은 보내기/한 번에 한 바이트를 수신 할 경우에, 당신은 그런 식으로 쓰기위한 레지스터를 캐스팅하고 읽을 필요가 :

BTW
readByte = (volatile uint8_t*)SPI1->DR; 
(volatile uint8_t*)SPI1->DR = writeByte; 

- 왜 당신이 CMSIS 헤더가 제공 # 정의를 사용하지 않는? SPI1_MASTER_MODE ...

+0

힌트를 보내 주셔서 감사합니다. 참조 설명서에서 그 내용을 훑어보아야합니다. 그래서 데이터가 WORD 또는 BYTE로 보내지는지 정말로 신경 쓰지 않으면 포인터를 1 대신 2 씩 증가시킬 수 있습니까? 또한 디버거에서 ** spi_init()가 완료된 후 ** CR1 ** 필드가 SPI 활성화 필드가 0으로 설정되었음을 알았습니다. 정상적인 동작입니까, 아니면 조사해야합니까? – saukijan

+0

@saukijan - 한 번에 8 비트 또는 16 비트 데이터를 보낼 수 있지만 포인터를 증가 시키면 버퍼에서 2 바이트를 읽고 쓸 수 있어야합니다. 현재 1 바이트를 읽고이를 16 비트 '0x00 ??'로 DR 레지스터에 씁니다. 일반적으로 새로운 STM32 장치의 SPI는 까다 롭습니다 ... –

+0

@saukijan - 편집 된 답변을 살펴보십시오. 이제 (주된) 문제를 해결해야합니다. –