'STM32_Study'에 해당되는 글 13건

  1. 2008.02.25 [STM32] I2C테스트 (1)
  2. 2008.02.15 [STM32]GPIO
  3. 2008.02.15 [STM32] CLOCK
[ST_MICRO]/STM322008. 2. 25. 07:57

[STM32] I2C테스트

STM32 I2C테스트
 
일단 STM32 I2C 테스트 하면서 필요한 사항을 정리해 본다.
 
STM32와 MSP430(2013)을 이용하한 기본 I2C 테스트 보드
 
 
테스트 예제소스
 
STM32 유저 가이드
 

I2C블럭도
STM32는 2개의 I2C모듈이 있고 그림과 같은 블록도로
 
I2C1
PB6 - SCL
PB7 - SDA
 
I2C2
PB10 - SCL
PB11 - SDA
 
 
초기화
void i2c_init(void)
{
    I2C_InitTypeDef  I2C_InitStructure; 
 
 //1)클럭 초기화 I2C1 and Periph clock enable
 RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C2, ENABLE);   
 //GPIOB Periph clock enable
 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
 
 //2)Configure I2C2 pins: SCL and SDA
 GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_10 | GPIO_Pin_11;
 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;
 GPIO_Init(GPIOB, &GPIO_InitStructure);
 
 //3)I2C1 configuration
 I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
 I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;
 I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
 //  I2C_InitStructure.I2C_OwnAddress1 = I2C1_SLAVE_ADDRESS7; 
 I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
 I2C_InitStructure.I2C_ClockSpeed = I2C_Speed;
 I2C_Init(I2C2, &I2C_InitStructure);
 
 I2C_Cmd(I2C_ID, ENABLE);
}
 
 
I2C 프로토콜
 

 
I2C Read 동작
아래 블럭도와 같이 코딩을하면된다.
 

STM32 I2C를 테스트 하면가 가장 고생했던 점은 처음 한번은 잘 동작하고 어떨때 Read가 되지 않은 현상 발생 한다.
코드상 문제는 없는데... 딜레이도 주고 여러가지 다 해봤지만 원인을 찾을 수가 없었다.  
결국 2일을 고생하고 찾아낸 결론은 I2C_Cmd() 함수로 리셋을 해주면 문제없이 잘 동작한다. 그래서 i2c_start()함수 초기에 항상 리셋을 걸고 있다
 
unsigned char i2c_start(unsigned char address)
{
 I2C_Cmd(I2C_ID, DISABLE);
 I2C_Cmd(I2C_ID, ENABLE);
 
 
큰 부하는 아니지만 속도가 문제라면 함수가 아니라 메크로로 정의해 둘수도 있겠다.
 
 #define CR1_PE_Set              ((u16)0x0001)
 #define CR1_PE_Reset            ((u16)0xFFFE)

 I2C_ID->CR1 = CR1_PE_Reset;
 I2C_ID->CR1 = CR1_PE_Set; 
 



STM32 I2C에서 또한번 나를 당혹하게한다.
I2C를 이용하는 센서 테스트중 Read시에 EV7체크하는 부분이 있는데... 아무리해도 이 값이 세트되지 않는 현상이 발생하기에 Address Write이후 EV6 체크하는 부분을 삭제하니 정상동작한다.
이게 무슨일인지...다른 MCU에서 잘동작히니 디바이스 문제는 아닌것 같고... 아무튼 해결은 되었지만 맘에 들지 않는다
 
ST예제 STM32 I2C 코드
  /* Send address for read */
  I2C_Send7bitAddress(I2C1, EEPROM_ADDRESS, I2C_Direction_Receiver);
 
  /* Test on EV6 and clear it */
 while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED))
 
 while(NumByteToRead) 
 {
    /* Test on EV7 and clear it */
    if(I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED)) 
    {     
      /* Read a byte from the EEPROM */
      *pBuffer = I2C_ReceiveData(I2C1);
 
 
 
내가 수정한 STM32 I2C코드
 //Send address for read
 I2C_Send7bitAddress(I2C_ID, LIS3L02_I2C_ADDR, I2C_Direction_Receiver);
 
 //Test on EV6 and clear it
 while(!I2C_CheckEvent(I2C_ID, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED));
 
    while(1) 
    {
        //Test on EV7 and clear it
        if(I2C_CheckEvent(I2C_ID, I2C_EVENT_MASTER_BYTE_RECEIVED)) 
        {     
            data = I2C_ReceiveData(I2C_ID);
            break;
        }  
    }




이상하게 STM32 I2C에만 문제가 있네...
연속적인데이터를 수집하려하니 문제가 있다. start()에서 100us정도의 딜레이를 주니 잘동작은 하는데... 아무래도 나중에 속도문제가 될것 같다...
 
unsigned char i2c_start(unsigned char address)
{
    Delay_us(100); 
      :
}

테스트 동영상
기울기에따라 I2C 가속도센서 데이터를 그래프로 표시



테스트 코드 (STM32 M-Tyep EVM)

Delay없이 사용할 수 있도록 수정한 STM32 최종 I2C start() 함수  소스
unsigned char i2c2_start(unsigned char address)
{
    if(address&I2C_READ)
    {
  /* Send STRAT condition a second time */ 
  I2C_GenerateSTART(I2C2, ENABLE);
  
  /* Test on EV5 and clear it */
  while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT));
 
  /* Send EEPROM address for read */
  I2C_Send7bitAddress(I2C2, address-1, I2C_Direction_Receiver);
  /* Test on EV6 and clear it */
  while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED));
    }
    else
    {
  /* While the bus is busy */
  while(I2C_GetFlagStatus(I2C2, I2C_FLAG_BUSY));
 
  /* Send START condition */
  I2C_GenerateSTART(I2C2, ENABLE);
 
  /* Test on EV5 and clear it */
  while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT));
 
  /* Send EEPROM address for write */
  I2C_Send7bitAddress(I2C2, address, I2C_Direction_Transmitter);
  /* Test on EV6 and clear it */
  while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
  
  /* Clear EV6 by setting again the PE bit */
  I2C_Cmd(I2C2, ENABLE);  
    }  
  
   return 0;  
}
Posted by nexp

댓글을 달아 주세요

  1. 샤인

    관리자의 승인을 기다리고 있는 댓글입니다

    2011.09.16 11:35 [ ADDR : EDIT/ DEL : REPLY ]

[ST_MICRO]/STM322008. 2. 15. 19:09

[STM32]GPIO

[STM32]GPIO



특징

  • 80 Standard I/Os (5V tolerant, 20 mA drive)
  • 18 MHz Toggling
  • Configurable Output Speed up to 50 MHz
  • Up to 16 Analog Inputs
  • Alternate Functions pins (like USARTx, TIMx, I2Cx, SPIx, CAN, USB…)
  • All I/Os can be set-up as external interrupt (up to 16 lines at time)
  • One I/O can be used as Wake-Up from STANDBY (PA.00)
  • One I/O can be set-up as Tamper Pin (PC.13)
  • All Standard I/Os are shared in 5 ports (GPIOA..GPIOE)
  • Atomic Bit Set and Bit Reset using BSRR and BRR registers
  • Locking mechanism to avoid spurious write in the IO registers

GPIO관련 registers
CRL
 - Port Control Register low
CRH - Port Control Register High
IDR - Input Data Register
ODR Output Data Register
BSRR Bit Set Reset Register
BRR Bit Reset Register
LCKR Lock Register
EVCR Event Control Register
MAPR Remap Debug and AF Register
EXTICR EXTI Line 0 to Line 15 Configuration Register


GPIO Configuration
고속을 요하지 않는 포트 설정은 간단히 GPIO_DeInit()함수에 원하는 설정값 구조체를 입력하면 되므로 쉽게 설정가능한다.


GPIO클럭 APB2를 eable하고 원하는 포트와 클럭속도, 입출력 모드를 설정하면 GPIO Configuration이 된다.
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(LED1_PORT, &GPIO_InitStructure)


void GPIO_DeInit(GPIO_TypeDef* GPIOx)

{

  switch (*(u32*)&GPIOx)

  {

    case GPIOA_BASE:

      RCC_APB2PeriphResetCmd(RCC_APB2Periph_GPIOA, ENABLE);

      RCC_APB2PeriphResetCmd(RCC_APB2Periph_GPIOA, DISABLE);

      break;

    case GPIOB_BASE:

      RCC_APB2PeriphResetCmd(RCC_APB2Periph_GPIOB, ENABLE);

      RCC_APB2PeriphResetCmd(RCC_APB2Periph_GPIOB, DISABLE);

      break;

    case GPIOC_BASE:

      RCC_APB2PeriphResetCmd(RCC_APB2Periph_GPIOC, ENABLE);

      RCC_APB2PeriphResetCmd(RCC_APB2Periph_GPIOC, DISABLE);

      break;

    case GPIOD_BASE:

      RCC_APB2PeriphResetCmd(RCC_APB2Periph_GPIOD, ENABLE);

      RCC_APB2PeriphResetCmd(RCC_APB2Periph_GPIOD, DISABLE);

      break;

     

    case GPIOE_BASE:

      RCC_APB2PeriphResetCmd(RCC_APB2Periph_GPIOE, ENABLE);

      RCC_APB2PeriphResetCmd(RCC_APB2Periph_GPIOE, DISABLE);

      break;           

    default:

      break;

  }

}


포트출력
IO포트가 출력으로 설정되면 Output Buffer가 사용가능해 진다.
따라서 포트를 0 또는 1로 출력하기 위해 BSRR(Bit Set Reset Register), BRR(Bit Reset Register) 레지스터에 값을 출력하면 된다.

//GPIO핀을 high로 출력
GPIOx->BSRR = GPIO_Pin

//GPIO핀을 low로 출력
GPIOx->BRR = GPIO_Pin

기존 코드와 호환성도 있고 해서 sbi, cbi로 정의 했다.
#define sbi(Port, Bit)     Port->BSRR = Bit
#define cbi(Port, Bit)     Port->BRR = Bit




ODR(Output Data Register)는 쓰고 읽을 수  있으므로 비트토글에 있어 유용하게 사용할 수 있다.
GPIOx->ODR ^= GPIO_Pin

보드상의 LED를 제어하기 위해 아래와 같이 설정하였다.
#define LED1_BIT         GPIO_Pin_8
#define LED1_PORT      GPIOB

#define Led1Off()         LED1_PORT->BRR |= LED1_BIT
#define Led1On()         LED1_PORT-> |= LED1_BIT
#define Led1Toggle()   LED1_PORT->ODR ^= LED1_BIT







JATG핀을 GPIO로 사용하기 위해 처리해야 할 사항
* STM32에서 JTAG핀은 RCC_APB2Periph_AFIO 클럭을 설정해야 정상동작 한다.

    //Enable GPIOA, GPIOB and AFIO clocks
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO, ENABLE);    
 
    //Disable the Serial Wire Jtag Debug Port SWJ-DP
    GPIO_PinRemapConfig(GPIO_Remap_SWJ_Disable, ENABLE);

    //Configure PA.13 (JTMS/SWDAT), PA.14 (JTCK/SWCLK) and PA.15 (JTDI) as output push-pull
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    //Configure PB.03 (JTDO) and PB.04 (JTRST) as output push-pull
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3 | GPIO_Pin_4;
    GPIO_Init(GPIOB, &GPIO_InitStructure);


SWD 를 이용하고 나머지 JTAG핀을 GPIO로 사용하고 싶다면 GPIO_PinRemapConfig()함수에서 GPIO_Remap_SWJ_JTAGDisable 를 설정하면 된다.


#define GPIO_Remap_SWJ_NoJTRST     ((u32)0x00300100)  /* Full SWJ Enabled (JTAG-DP + SW-DP) but without JTRST */

#define GPIO_Remap_SWJ_JTAGDisable ((u32)0x00300200)  /* JTAG-DP Disabled and SW-DP Enabled */

#define GPIO_Remap_SWJ_Disable     ((u32)0x00300400)  /* Full SWJ Disabled (JTAG-DP + SW-DP) */



고속으로 GPIO를 제어 하기 위해 ST에서 제공하는 함수로는 한계가 있다.
직접 레지스터를 제어 해야 한다.

특히 GPIO 입출력 방향을 자주 바꾸어야 할 경우 아무래도 제공함수는 설정하는것이 너무 많다.
일단 PORTB 하위를 Data포트로 사용하기 때문에 아래와 같이 정의해서 사용하면 편리하다.

#define GPIOB_DIR_IN()     GPIOB->CRL = 0x88888888;
#define GPIOB_DIR_OUT()     GPIOB->CRL = 0x33333333;





Posted by nexp

댓글을 달아 주세요

[ST_MICRO]/STM322008. 2. 15. 10:31

[STM32] CLOCK

[STM32] CLOCK
클럭 소스는 내부 8Mhz의 RC오실레이터나 외부 4~16Mhz크리스탈, OSC32 32Khz로 공급된다.
SYSCLK(System Clock) sources
 HSI, HSE, PLL에서 공급되며 AHB, APB1/2, ADC and TIM clocks 으로 사용 한다.
 
USBCLK(USB Clock)
내부 PLL으로 부터 생성해서 USB 엔진에 공급된다.
 
RTCCLK(RTC Clock)
LSE, LSI, HSE/128 으로 공급된다.
 

CSS(Clock Security System)
HSE실패를 대비한 백업클럭
 
 
HCLK
코어 클럭으로 72Mhz까지 가능
 
 
 
STM32 전체 Clock 구조



BusMatrix와 Harvard architecture로 SRAM, Flash, Peripherals, DMA를 동시에 접근가능해 병목현상이 상당히 줄어 속도를 향상 시겼다고 함.

클럭설정을 위해 먼저 내부클럭(HSI), 외부클럭 (HSE)를 사용할것인지를 설정한다.
ST에서 제공하는 RCC관련 stm32f10x_rcc.c 파일에서 RCC_HSEConfig()함수를 사용해서 RCC_HSE_ON, RCC_HSE_Bypass를 결정할 수 있다.
 
RCC_PLLConfig함수에서 PLL설정 가능하다.
 
    /* PLLCLK = 8MHz * 9 = 72 MHz */
    RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);
 
 
 
HCLK, PCLK1 , PCLK2 등 클럭 설정을 RCC_Configuration()함수로 만들어 관리하면 편하게 사용할 수 있다.
 
void RCC_Configuration(void)
{
  /* RCC system reset(for debug purpose) */
  RCC_DeInit();
  /* Enable HSE */
  RCC_HSEConfig(RCC_HSE_ON);
  /* Wait till HSE is ready */
  HSEStartUpStatus = RCC_WaitForHSEStartUp();
  if(HSEStartUpStatus == SUCCESS)
  {
    /* Enable Prefetch Buffer */
    FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
    /* Flash 2 wait state */
    FLASH_SetLatency(FLASH_Latency_2);
 
    /* HCLK = SYSCLK */
    RCC_HCLKConfig(RCC_SYSCLK_Div1);

 
    /* PCLK2 = HCLK */
    RCC_PCLK2Config(RCC_HCLK_Div1);
   
    /* PCLK1 = HCLK/2 */
    RCC_PCLK1Config(RCC_HCLK_Div2);   //run 72Mhz @Div2

    /* PLLCLK = 8MHz * 9 = 72 MHz */
    RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);
   
    /* Enable PLL */
    RCC_PLLCmd(ENABLE);
    /* Wait till PLL is ready */
    while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET)
    {
    }
    /* Select PLL as system clock source */
    RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
    /* Wait till PLL is used as system clock source */
    while(RCC_GetSYSCLKSource() != 0x08)
    {
    }
  }
}

- PCLK1 은 Timer 등 많은 페리가 연결되어 있는데 Div2일때 최대 72Mhz 로 동작한다.
Posted by nexp

댓글을 달아 주세요