2017-10-29 96 views
1

SPI를 사용하여 GPIO 레지스터에 쓰면 MCP23S09에서 LED를 활성화하려고합니다.STM32 SPI가 예상대로 작동하지 않습니다.

보드에는 두 개의 칩이 있으며, 하나는 입력 용이고 다른 하나는 출력 용이므로 LED가 있습니다.

필자는 모든 것을 연결 했으므로 CH2를 로우로 설정하고 MOSI 및 SCK 핀을 내 마이크로 컨트롤러에 연결했다.

저는 CubeMX 소프트웨어와 함께 Nucleo STM32F411을 사용하고 있습니다. 따라서 레지스터를 사용하여 기능을 활성화하려고합니다.

하지만 유감스럽게도 IO 확장기에는 LED가 켜지지 않습니다.

내가 시도한 다음 것은 STM32duino이므로 내 보드에 Arduino 코드를 쓸 수 있습니다. 그러나 내가 아는 한, 이것은 HAL 라이브러리 위에있는 또 다른 계층 일뿐입니다.

놀랍게도 제대로 작동했습니다. 그것은 동일한 코드 조각입니다. Arduino에서 약간 변경되었습니다.

그러나 CubeMX에서 생성 된 HAL 라이브러리를 사용할 때 왜 작동하지 않는지 아직 이해할 수 없습니다.

아두 이노 코드 :

#include <SPI.h> 

#define IODIR 0x00 
#define IPOL 0x01 
#define GPINTEN 0x02 
#define DEFVAL 0x03 
#define INTCON 0x04 
#define IOCON 0x05 
#define GPPU 0x06 
#define INTF 0x07 
#define INTCAP 0x08 
#define GPIO 0x09 
#define OLAT 0x0A 

#define OPCODEW 0x40 
#define OPCODER 0x41 

// CS0 -> D2 
const int slaveAPin = 2; 

// CS1 -> D3 
const int slaveBPin = 3; 

// LED VAL 
const uint8_t value = ~0x3F; 


void setup() { 
    // put your setup code here, to run once: 
    // initialize SPI: 
    SPI.begin(); //Initialize the SPI_1 port. 
    SPI.setBitOrder(MSBFIRST); // Set the SPI_1 bit order 

    SPI.setDataMode(SPI_MODE0); //Set the SPI_1 data mode 0 
    SPI.setClockDivider(SPI_CLOCK_DIV64);  

    pinMode (slaveAPin, OUTPUT); // First chip for inputs 
    pinMode (slaveBPin, OUTPUT); // Second chip for outputs 

    digitalWrite (slaveAPin, HIGH); 
    digitalWrite (slaveBPin, HIGH); 

} 

void loop() { 
    // configuration led-io-expander 
    sendDataSPI(IOCON, 0x20); 

    // all pins = output 
    sendDataSPI(IODIR, 0x00); 

    // Enable LEDS 
    sendDataSPI(GPIO, value); 
} 


void sendDataSPI(uint8_t reg, uint8_t value){ 
    digitalWrite (slaveBPin, LOW); // Take slave-select low 
    SPI.transfer(OPCODEW); // Send the MCP23S09 opcode, and write byte 
    SPI.transfer(reg); // Send the register we want to write 
    SPI.transfer(value); // Send the byte 
    digitalWrite (slaveBPin, HIGH); // Take slave-select high 
} 

STM32 HAL :

/** 
    ****************************************************************************** 
    * File Name   : main.c 
    * Description  : Main program body 
    ****************************************************************************** 
    ** This notice applies to any and all portions of this file 
    * that are not between comment pairs USER CODE BEGIN and 
    * USER CODE END. Other portions of this file, whether 
    * inserted by the user or by software development tools 
    * are owned by their respective copyright owners. 
    * 
    * COPYRIGHT(c) 2017 STMicroelectronics 
    * 
    * Redistribution and use in source and binary forms, with or without modification, 
    * are permitted provided that the following conditions are met: 
    * 1. Redistributions of source code must retain the above copyright notice, 
    *  this list of conditions and the following disclaimer. 
    * 2. Redistributions in binary form must reproduce the above copyright notice, 
    *  this list of conditions and the following disclaimer in the documentation 
    *  and/or other materials provided with the distribution. 
    * 3. Neither the name of STMicroelectronics nor the names of its contributors 
    *  may be used to endorse or promote products derived from this software 
    *  without specific prior written permission. 
    * 
    * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
    * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
    * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 
    * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 
    * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 
    * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 
    * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
    * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 
    * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
    * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
    * 
    ****************************************************************************** 
    */ 
/* Includes ------------------------------------------------------------------*/ 
#include "main.h" 
#include "stm32f4xx_hal.h" 

/* USER CODE BEGIN Includes */ 

/* USER CODE END Includes */ 

/* USER CODE BEGIN Defines */ 
#define IODIR 0x00 
#define IPOL 0x01 
#define GPINTEN 0x02 
#define DEFVAL 0x03 
#define INTCON 0x04 
#define IOCON 0x05 
#define GPPU 0x06 
#define INTF 0x07 
#define INTCAP 0x08 
#define GPIO 0x09 
#define OLAT 0x0A 

#define OPCODEW  0x40 
#define OPCODER 0x41 

#define SPI_TRANSFER_TIMEOUT 1000 
/* USER CODE END Defines */ 

/* Private variables ---------------------------------------------------------*/ 
SPI_HandleTypeDef hspi1; 

UART_HandleTypeDef huart2; 

/* USER CODE BEGIN PV */ 
/* Private variables ---------------------------------------------------------*/ 

/* USER CODE END PV */ 

/* Private function prototypes -----------------------------------------------*/ 
void SystemClock_Config(void); 
static void MX_GPIO_Init(void); 
static void MX_SPI1_Init(void); 
static void MX_USART2_UART_Init(void); 
void sendDataSPI(uint8_t reg, uint8_t value); 
int fgetc(FILE *f); 
int fputc(int c, FILE *f); 
/* USER CODE BEGIN PFP */ 
/* Private function prototypes -----------------------------------------------*/ 

/* USER CODE END PFP */ 

/* USER CODE BEGIN 0 */ 

/* USER CODE END 0 */ 

int main(void) 
{  
    // LED VAL 
    uint8_t value = 0x3F; 

    /* USER CODE BEGIN 1 */ 

    /* USER CODE END 1 */ 

    /* MCU Configuration----------------------------------------------------------*/ 

    /* Reset of all peripherals, Initializes the Flash interface and the Systick. */ 
    HAL_Init(); 

    /* USER CODE BEGIN Init */ 

    /* USER CODE END Init */ 

    /* Configure the system clock */ 
    SystemClock_Config(); 

    /* USER CODE BEGIN SysInit */ 

    /* USER CODE END SysInit */ 

    /* Initialize all configured peripherals */ 
    MX_GPIO_Init(); 
    MX_SPI1_Init(); 
    MX_USART2_UART_Init(); 


    /* USER CODE BEGIN 2 */ 

    /* USER CODE END 2 */ 

    /* Infinite loop */ 
    /* USER CODE BEGIN WHILE */ 
    while (1) 
    { 
    /* USER CODE END WHILE */ 

    /* USER CODE BEGIN 3 */ 
     // configuration led-io-expander 

     sendDataSPI(IOCON, 0x20); 

     // all pins = output 
     sendDataSPI(IODIR, 0x00); 

     // Enable LEDS 
     sendDataSPI(GPIO, value); 

    } 
    /* USER CODE END 3 */ 

} 

// REGISTER, VALUE 
void sendDataSPI(uint8_t reg, uint8_t value){ 
     HAL_GPIO_WritePin(CS1_GPIO_Port, CS1_Pin, GPIO_PIN_RESET); // Take slave-select low 
     HAL_SPI_Transmit(&hspi1,(uint8_t *)OPCODEW,sizeof(uint8_t),SPI_TRANSFER_TIMEOUT); // Send the MCP23S09 opcode, and write bit 
     HAL_SPI_Transmit(&hspi1,(uint8_t *)&reg,sizeof(uint8_t),SPI_TRANSFER_TIMEOUT); // Send the register we want to write 
     HAL_SPI_Transmit(&hspi1,(uint8_t *)&value,sizeof(uint8_t),SPI_TRANSFER_TIMEOUT); // Send the byte 
     HAL_GPIO_WritePin(CS1_GPIO_Port, CS1_Pin, GPIO_PIN_SET); // Take slave-select high 
} 

int fputc(int c, FILE *f) { 
    return (HAL_UART_Transmit(&huart2, (uint8_t *)&c,1,HAL_MAX_DELAY)); 
} 

int fgetc(FILE *f) { 
    char ch; 
    HAL_UART_Receive(&huart2,(uint8_t*)&ch,1,HAL_MAX_DELAY); 
    return (ch); 
} 

/** System Clock Configuration 
*/ 
void SystemClock_Config(void) 
{ 

    RCC_OscInitTypeDef RCC_OscInitStruct; 
    RCC_ClkInitTypeDef RCC_ClkInitStruct; 

    /**Configure the main internal regulator output voltage 
    */ 
    __HAL_RCC_PWR_CLK_ENABLE(); 

    __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1); 

    /**Initializes the CPU, AHB and APB busses clocks 
    */ 
    RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI; 
    RCC_OscInitStruct.HSIState = RCC_HSI_ON; 
    RCC_OscInitStruct.HSICalibrationValue = 16; 
    RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; 
    RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI; 
    RCC_OscInitStruct.PLL.PLLM = 16; 
    RCC_OscInitStruct.PLL.PLLN = 336; 
    RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV4; 
    RCC_OscInitStruct.PLL.PLLQ = 4; 
    if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) 
    { 
    _Error_Handler(__FILE__, __LINE__); 
    } 

    /**Initializes the CPU, AHB and APB busses clocks 
    */ 
    RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK 
           |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2; 
    RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; 
    RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; 
    RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2; 
    RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; 

    if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK) 
    { 
    _Error_Handler(__FILE__, __LINE__); 
    } 

    /**Configure the Systick interrupt time 
    */ 
    HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/1000); 

    /**Configure the Systick 
    */ 
    HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK); 

    /* SysTick_IRQn interrupt configuration */ 
    HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0); 
} 

/* SPI1 init function */ 
static void MX_SPI1_Init(void) 
{ 
    /* SPI1 parameter configuration*/ 
    hspi1.Instance = SPI1; 
    hspi1.Init.Mode = SPI_MODE_MASTER; 
    hspi1.Init.Direction = SPI_DIRECTION_2LINES; 
    hspi1.Init.DataSize = SPI_DATASIZE_8BIT; 
    hspi1.Init.CLKPolarity = SPI_POLARITY_LOW; 
    hspi1.Init.CLKPhase = SPI_PHASE_1EDGE; 
    hspi1.Init.NSS = SPI_NSS_SOFT; 
    hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_64; 
    hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB; 
    hspi1.Init.TIMode = SPI_TIMODE_DISABLE; 
    hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE; 
    hspi1.Init.CRCPolynomial = 10; 
    if (HAL_SPI_Init(&hspi1) != HAL_OK) 
    { 
    _Error_Handler(__FILE__, __LINE__); 
    } 

} 

/* USART2 init function */ 
static void MX_USART2_UART_Init(void) 
{ 

    huart2.Instance = USART2; 
    huart2.Init.BaudRate = 115200; 
    huart2.Init.WordLength = UART_WORDLENGTH_8B; 
    huart2.Init.StopBits = UART_STOPBITS_1; 
    huart2.Init.Parity = UART_PARITY_NONE; 
    huart2.Init.Mode = UART_MODE_TX_RX; 
    huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE; 
    huart2.Init.OverSampling = UART_OVERSAMPLING_16; 
    if (HAL_UART_Init(&huart2) != HAL_OK) 
    { 
    _Error_Handler(__FILE__, __LINE__); 
    } 

} 

/** Configure pins as 
     * Analog 
     * Input 
     * Output 
     * EVENT_OUT 
     * EXTI 
*/ 
static void MX_GPIO_Init(void) 
{ 

    GPIO_InitTypeDef GPIO_InitStruct; 

    /* GPIO Ports Clock Enable */ 
    __HAL_RCC_GPIOC_CLK_ENABLE(); 
    __HAL_RCC_GPIOH_CLK_ENABLE(); 
    __HAL_RCC_GPIOA_CLK_ENABLE(); 
    __HAL_RCC_GPIOB_CLK_ENABLE(); 

    /*Configure GPIO pin Output Level */ 
    HAL_GPIO_WritePin(CS0_GPIO_Port, CS0_Pin, GPIO_PIN_RESET); 

    /*Configure GPIO pin Output Level */ 
    HAL_GPIO_WritePin(CS1_GPIO_Port, CS1_Pin, GPIO_PIN_RESET); 

    /*Configure GPIO pin : B1_Pin */ 
    GPIO_InitStruct.Pin = B1_Pin; 
    GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING; 
    GPIO_InitStruct.Pull = GPIO_NOPULL; 
    HAL_GPIO_Init(B1_GPIO_Port, &GPIO_InitStruct); 

    /*Configure GPIO pin : CS0_Pin */ 
    GPIO_InitStruct.Pin = CS0_Pin; 
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; 
    GPIO_InitStruct.Pull = GPIO_NOPULL; 
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; 
    HAL_GPIO_Init(CS0_GPIO_Port, &GPIO_InitStruct); 

    /*Configure GPIO pin : CS1_Pin */ 
    GPIO_InitStruct.Pin = CS1_Pin; 
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; 
    GPIO_InitStruct.Pull = GPIO_NOPULL; 
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; 
    HAL_GPIO_Init(CS1_GPIO_Port, &GPIO_InitStruct); 

} 

/* USER CODE END 4 */ 

답변

3

당신은 SPI 전송을 기다리지 않는다 귀하의 sendDataSPI 함수에서 다음 전송을 시작하기 전에 완료해야합니다. 다음과 같이 수정해야합니다

void sendDataSPI(uint8_t reg, uint8_t value){ 
     HAL_GPIO_WritePin(CS1_GPIO_Port, CS1_Pin, GPIO_PIN_RESET); // Take slave-select low 

     HAL_SPI_Transmit(&hspi1,(uint8_t *)OPCODEW,sizeof(uint8_t),SPI_TRANSFER_TIMEOUT); // Send the MCP23S09 opcode, and write bit 
     while(HAL_SPI_GetState(&hspi1) != HAL_SPI_STATE_READY); 

     HAL_SPI_Transmit(&hspi1,(uint8_t *)&reg,sizeof(uint8_t),SPI_TRANSFER_TIMEOUT); // Send the register we want to write 
     while(HAL_SPI_GetState(&hspi1) != HAL_SPI_STATE_READY); 

     HAL_SPI_Transmit(&hspi1,(uint8_t *)&value,sizeof(uint8_t),SPI_TRANSFER_TIMEOUT); // Send the byte 
     while(HAL_SPI_GetState(&hspi1) != HAL_SPI_STATE_READY); 

     HAL_GPIO_WritePin(CS1_GPIO_Port, CS1_Pin, GPIO_PIN_SET); // Take slave-select high 
} 

것은 또한이 라인은 단지 0x40이 쓰레기를 보내고 없습니다. 당신이 uint8_t*OPCODEW을 캐스팅

HAL_SPI_Transmit(&hspi1,(uint8_t *)OPCODEW,sizeof(uint8_t),SPI_TRANSFER_TIMEOUT); // Send the MCP23S09 opcode, and write bit 

주의 때문에 실제로는 데이터와 포인터 (어떤 임의의 메모리를 가리키는) 및하지로 0x40을 전달합니다.

+1

도움을 주셔서 감사합니다. 실제로 잘못된 주소를 가리키는 OPCODEW가 원인이었습니다. 프로그램이 그 동안 잘 작동하는 것 같습니다 (HAL_SPI_GetState (& hspi1)! = HAL_SPI_STATE_READY); 그러나 나는 전송이 완료 될 때까지 기다리는 것이 정말로 중요하다고 본다. – stickfigure4

+0

@ stickfigure4 듣기가 좋았습니다. 이 ('while (HAL_SPI_GetState (& hspi1)! = HAL_SPI_STATE_READY);)은 라이브러리의 초기 버그 였을 것입니다. –