반응형

보다 많은 number의 범위를 보장하는 signed extend number funtion 함수이다. 최대 32자리까지 지원하는 unsigned bit number를 부호있는 숫자로 형변환을 할 때에 유용하게 쓰일 함수다.

 

참고로 "1L"의 의미는 여러 종류의 데이터 타입 중에 long type 이 있는데, 이는 int type 보다 큰 memory size를 차지하며, 일반적으로 4bytes(32bit)의 memory size를 가지는 unsigned, signed type으로 형변환을 할 때에 이를 모두 표현할 수 있는 long type 이 제격이다.

/* To convert the sing extension number from the target number */  
long SignExtensionRedunction(uint32_t number, int length)  
{  
     long extend_number = (long)number;  
     long mask = 1L<<(length-1);  

     if (length<32) {  
          // fill the zero bit unless the same bit after the AND bit operation 
          extend_number = extend_number&((1<<length)-1); 
         }  
     return (long)((extend_number^mask)-mask);  
}

 

반응형
반응형

2015년 6월 메르스 사태 시절에 결혼했던 사람으로 나름 기억하고 있는 사실들이 있다.
당시 국가에서 중동발 메르스 감염을 은폐하길 급급했고, 감염자는 코로나19 감염자보다는 적었지만, 결과적으로 메르스 감염자의 치사율은 무려 30프로에 도달했었던 공포스러웠던(?) 시기였다. 그래도 낙타 근처에 가지말라는 정부의 예방 수칙에 황당함의 그자체였다.
하지만 코로나19 사태는 확산의 시발점이 된 신천지 관련 31번 환자가 나타나기 전까지는 국가가 긴장을 늦췄던게 아쉬웠지만 그만큼 투명하고 속도전을 펼쳐서 금번 대구, 경북발 판데믹 현상이 대유행하기 전에 시간을 조금이나마 벌었던게 유효했다고 본다.
지금까지도 고생하시는 정은경 질병관리본부장 비롯해서 방역담당자들의 끝없는 노력과 헌신에 감사드린다.
만약 현재 정부가 아니었다면, 신종플루와 메르스 감염 유행 시기를 지켜본 본인으로서는 지금 당장 일본의 신뢰할 수 없는 대응 사례만 봐도 저절로 답이 나온다.
그리고 아직도 정부를 향해 중국인 입국 금지를 주장하는 사람들이 많은데, 현재 확진자 대부분 신천지발 한국인이 감염원으로서 95% 이상 차지한다. 멀리 안가도 중국인 입국 금지한(?) 이탈리아, 이란에서는 벌써 수많은 확진자와 사망자가 발생하고 있다.

위의 사례가 말해주듯이, 어차피 발생한 감염병이니 지역적인 비하 및 책임론을 대두하는 것보다는 인류가 모두 마음을 합하여 과거 홍역 및 스페인 독감 같은 결과를 마주하지 않도록 전세계가 마음을 합해서 바이러스를 이겨내는 것이 보기 좋다.

마지막으로 모두들 건강한 삶과 하루가 함께하길 기도하며 글을 마친다.

반응형

'Life > Story' 카테고리의 다른 글

2023년 3월 봄날에...  (0) 2023.03.15
2022년 임인년 새해 복 많이 받으세요.  (0) 2022.01.18
오랜만에 글을 남긴다.  (0) 2016.05.09
보더로서 3시즌 째, 기본적인 턴~  (0) 2013.01.28
2012년도 연말정산!  (0) 2013.01.16
반응형

STM32F103 series로 maximum 72Mhz system clock를 사용하려면 외부 12Mhz oscillator를 실장하여 HSE (High Speed External) crystal output clock frequency mode로 PLL multiplication factor 제어하여 6배 (PLL input clock x 6) 곱하여 72Mhz PLLCLK source로 사용하고 있었다.

 

그러나 external crystal 사용에 따른 부품 단가로 인하여 비용 절감(?)을 위해 internal 8Mhz RC Oscillator를 사용하여 HSI (High Speed Internal) crystal output clock frequency mode에서 아래 그림을 참고하면 2 분주 후, 16배 곱하여 maximum 64Mhz system clock를 사용할 수가 있다. 

 

(8Mhz / 2) x 16 = 64Mhz

 

그리고 internal 8Mhz RC Oscillator에 따른 HSI crystral output clock frequency mode의 장단점은 아래와 같다. 단지 main system clock frequency의 accuracy가 저하된다고 하는데, 과연 MCU 시스템에 큰 영향을 끼칠까?

 

The HSI RC oscillator has the advantage of providing a clock source at low cost (no external components). It also has a faster startup time than the HSE crystal oscillator however, even with calibration the frequency is less accurate than an external crystal oscillator or ceramicresonator.

 

참고로 STM32F103은 다음과 같이 3가지 종류의 clock source를 제공하고 있다.

 

- HSI Oscillator clock

- HSE Oscillator clock

- PLL clock

 

그리고 다음과 같이 maximum clock frequeny가 정의되어 있으므로, 적절하게 선정하여 사용 하도록 하자.

 

The maximum frequency of the AHB and the APB2 domains is 72 MHz. The maximum allowed frequency of the APB1 domain is 36 MHz.

 

위의 내용을 토대로 HSI mode를 사용하여 main 64Mhz system clock frequency를 출력하는 예제 코드는 아래와 같다.

 

void RCC_Configuration_HSI_64Mhz_without_USBclock(void)
{
    ErrorStatus HSIStartUpStatus;

    /* RCC system reset(for debug purpose) */
    RCC_DeInit();

    /* activate HSI (Internal High Speed oscillator) */
    RCC_HSICmd(ENABLE);

    /* Wait until RCC_FLAG_HSIRDY is ready */
    while (RCC_GetFlagStatus(RCC_FLAG_HSIRDY) == RESET);

    /* Enable Prefetch Buffer */
    FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);

    /* Flash 2 wait state */
    FLASH_SetLatency(FLASH_Latency_2);

    /* HCLK = SYSCLK */
    RCC_HCLKConfig(RCC_SYSCLK_Div1);// HCLK = 64 MHz, AHB

    /* PCLK1 = HCLK/2 */
    RCC_PCLK1Config(RCC_HCLK_Div2); // APB1 = 32 MHz

    /* PCLK2 = HCLK */
    RCC_PCLK2Config(RCC_HCLK_Div1); // APB2 = 64 MHz

    /* PLLCLK = (8MHz/2) * 16 = 64MHz */
    RCC_PLLConfig(RCC_PLLSource_HSI_Div2, RCC_PLLMul_16); // 64 MHz

    /* 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);
 
}

 

그러나 위의 과정을 거쳐서 USB clock를 사용하게 되면 문제가 발생되는데, 다음과 같이 USB clock를 사용하려면 48Mhz clock이 필요로하다. 그래서 PLL clock은 72Mhz 및 48Mhz의 output clock frequency가 필요하다.

 

The USB OTG FS 48 MHz clock which is derived from the PLL VCO clock (2 × PLLCLK), followed by a programmable prescaler (divide by 3 or 2). 

This selection is  made through the OTGFSPRE bit in the RCC_CFGR register. 

For proper USB OTG FSoperation, the PLL should be configured to output 72 MHz or 48 MHz.

 

위의 내용을 토대로 HSI mode를 사용하여 main 48Mhz system clock frequency로 설정하고 48Mhz USB clock 출력하는 예제 코드는 아래와 같다.

 

void RCC_Configuration_HSI_48Mhz_with_USBclock(void)
{
    ErrorStatus HSIStartUpStatus;

    /* RCC system reset(for debug purpose) */
    RCC_DeInit();

    /* activate HSI (Internal High Speed oscillator) */
    RCC_HSICmd(ENABLE);

    /* Wait until RCC_FLAG_HSIRDY is ready */
    while (RCC_GetFlagStatus(RCC_FLAG_HSIRDY) == RESET);

    /* Enable Prefetch Buffer */
    FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);

    /* Flash 2 wait state */
    FLASH_SetLatency(FLASH_Latency_2);

    /* HCLK = SYSCLK */
    RCC_HCLKConfig(RCC_SYSCLK_Div1);// HCLK = 48 MHz, AHB

    /* PCLK1 = HCLK/2 */
    RCC_PCLK1Config(RCC_HCLK_Div2); // APB1 = 24 MHz

    /* PCLK2 = HCLK */
    RCC_PCLK2Config(RCC_HCLK_Div1); // APB2 = 48 MHz

    /* PLLCLK = (8MHz/2) * 12 = 48MHz */
    RCC_PLLConfig(RCC_PLLSource_HSI_Div2, RCC_PLLMul_12); // 48 MHz

    /* 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);
 
}

 

참고로 USB clock 관련 설정은 아래와 같이 code 분리하여 프로그래밍을 하여도 된다.

 

/******************************************************************************* 
* Function Name  : Set_USBClock 
* Description    : Configures USB Clock input (48MHz) 
* Input          : None. 
* Return         : None. 
*******************************************************************************/ 
void Set_USBClock(void) 
{ 
    // Select USBCLK source 
    RCC_USBCLKConfig(RCC_USBCLKSource_PLLCLK_Div1); 

    // Enable the USB clock 
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_USB, ENABLE); 
}

/*******************************************************************************
* Function Name  : USB_Interrupts_Config
* Description    : Configures the USB interrupts
* Input          : None.
* Return         : None.
*******************************************************************************/
void USB_Interrupts_Config(void)
{
    NVIC_InitTypeDef NVIC_InitStructure;

    // 2 bit for pre-emption priority, 2 bits for subpriority
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);

    // Enable the USB interrupt
    NVIC_InitStructure.NVIC_IRQChannel = USB_LP_CAN1_RX0_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);

    // Enable the USB Wake-up interrupt
    NVIC_InitStructure.NVIC_IRQChannel = USBWakeUp_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);

    // Enable the DMA1 Channel1 Interrupt
    NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel1_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
}

/********************** main.c ***********************/
Set_USBClock();
USB_Interrupts_Config();
USB_Init(); // STM32 USB library at 'usb_init.c'

 

[부록]

System clock frequency를 48Mhz로 설정하고 나니, 문득 드는 생각이 있는데 GPIO_Speed_2MHz, GPIO_Speed_10MHz, GPIO_Speed_50MHz 의 설정값들이 있는데 GPIO Speed 50Mhz 설정에 따른 GPIO speed 관련 내용을 수집하여 보니, 해당 GPIO speed는 system clock과 관계없이 ARM core의 bus line speed에 대한 의미로 이해하면 된다. 어차피 아래 STM32F103 datasheet 내용을 참조하면 maximum 72Mhz system clock frequency 설정에 따른 maximum GPIO toggling speed는 18Mhz 이다. (GPIO speed 2Mhz의 장점은 EMI noise가 작아진다. 거꾸로 GPIO speed 50Mhz로 설정하면 EMI noise가 높아질 확률이다.)

 

GPIOs (general-purpose inputs/outputs)
Each of the GPIO pins can be configured by software as output (push-pull or open-drain), as input (with or without pull-up or pull-down) or as peripheral alternate function. Most of the GPIO pins are shared with digital or analog alternate functions. All GPIOs are high currentcapable. The I/Os alternate function configuration can be locked if needed following a specific sequence in order to avoid spurious writing to the I/Os registers. I/Os on APB2 with up to 18 MHz toggling speed. 

 

마지막으로 혹시 몰라서 HSE (High Speed External) crystal output clock frequency mode 관련 예제 코드도 공유한다.

 

void RCC_Configuration_HSE(void)
{
    ErrorStatus HSEStartUpStatus;

    /* 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); 

        /* PCLK1 = HCLK/2 */
        RCC_PCLK1Config(RCC_HCLK_Div2);

        /* PCLK2 = HCLK */
        RCC_PCLK2Config(RCC_HCLK_Div1); 

        /* ADCCLK = PCLK2/4 */
        RCC_ADCCLKConfig(RCC_PCLK2_Div6); 

        /* PLLCLK = 12MHz * 6 = 72 MHz */
        RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_6);

        /* 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);
    }    
}

 

반응형
반응형

바야흐로 2009년도에 가족과 춘천 여행 도중에 "춘천에 왔으니 닭갈비 먹어보자!" 라고 하면서 소양강댐 근처에 있는 "통나무집" 이라는 닭갈비 전문점에서 철판 닭갈비를 접하게 되었다.

http://tongnamushop.com/

 

통나무집닭갈비

백종원의 3대천왕에 나온 춘천 철판 닭갈비 맛집

tongnamushop.com

우선 위의 "통나무집" 온라인 쇼핑몰에서 원하는 수량만큼 전일 오후 3시 이전까지 택배 주문을 하면 익일 택배 도착하게 된다. 그럼 수령 후기 부터 맛있게 먹는 과정을 사진으로 남겨 보도록 한다.

택배를 주문하면 위와 같이 하얀 스티로폼에 포장되어 오는데, 요즘 환경 문제로 인해 좀더 친환경적인 포장 기법으로 배송되길 기대한다.
천천이 스티로폼 뚜껑을 개봉하면, 아이스팩 2개와 함께 신선한 냉장 상태로 포장되어 있는 것을 확인할 수가 있다.
오른쪽부터 양념된 냉장 닭갈비 2인분, 양념장, 각종 사리 및 양배추 등으로 나열되어 있는 것을 볼 수가 있다.
매번 조그만한 전기 후라이팬에 조리하는게 버거워서 이번에 큰맘먹고 40cm짜리 BSW BS-4113-HG 라는 후라이팬을 구매했다. 근데 너무 크다.
처음에 식초 세척을 한번 해주고, 본격적인 닭갈비 요리 전에 식용유를 적당히 둘러준다.
제일 먼저 냉장 닭갈비와 양념장 절반를 넣고 천천히 볶아가면서 양념장 비율을 조절한다.
적절한 양념장과 함께 맛있게 익어가는 닭갈비 요리. 확실히 광활한 전기 후라이팬 덕분에 편하게 요리를 하고 있다.
닭고기가 적당히 익어가는 찰나에 양배추 및 각종 사리를 함께 볶아주기 시작한다.
양념 비율이 부족하면 양념장을 좀더 추가해서 맜있게 볶아준다.
점점 맛있게 익어가는 닭갈비 요리.
드디어 먹음직스럽게 요리가 된 닭갈비 요리! 
닭갈비를 맛있게 먹고, 남은 것들을 잘게 잘라서 김치와 김, 참기름을 넣고 고슬밥과 함께 볶아서 먹으면 정말 맛있다.

 

닭갈비를 먹고 나니 아쉬운 점이 하나 생겼는데,

너무 오랜만에 먹어서 그런지 '동치미'가 너무 먹고 싶었고, 그게 아니라면 '쌈무'라도 있었으면 좋았을 것이라고 아쉬움이 남았지만, 그래도 저녁 식사로는 정말 맛있게 잘 먹었다.

다음 번에 기회가 되면 춘천 드라이브 할 겸 통나무집에 가서 먹방을 하러 가야겠다.

[2020/02/10 내용 추가]

지금까지 10년 가까이 '통나무집 온라인 쇼핑몰'에서 닭갈비 2인분을 주문하면서 늘 배송비 3천원을 함께 포함되어서 아까운 생각이 들었는데, 오늘 인터넷 검색을 하다가 동일한 상품이 대형 온라인 쇼핑몰(옥션, 지마켓, 11번가)에서 배송비 무료 조건으로 판매를 하고 있는 것을 발견하였다. 게다가 해당 쇼핑몰에서 제공하는 추가 할인 쿠폰을 적용하면 더욱 저렴해진다는...

상황을 살펴보니, CJmall이 판매대행 관련 계약을 맺고 CJmall에서 대형 온라인 쇼핑몰에서 독점판매를 하는 것처럼 보인다. 나야뭐 좀더 저렴하게 구매해서 맛있게 먹으면 되니 나름 좋은 소식이다.

 

(좀더 저렴한 온라인 주문 방법, 2020/02/10 기준)

1. 옥션 및 지마켓에서 '맛있는家 춘천 맛집 통나무집 닭갈비 - 매장동일상품' 및 '통나무집 닭갈비' 검색

2. 스마일 쿠폰 적용

3. 7~9% 할인된 컬쳐랜드(cultureland) 상품권을 구매하고, 스마일 캐시로 전환 충전하여 스마일 캐시로 주문

 

반응형
반응형

STM32F10x series MCU를 사용하면서 제공되는 stm32f10x_i2c.h / stm32f10x_i2c.c 관련 STM32 library를 사용한 hardware I2C example code를 공유한다.

 

# i2c_hw.h

#ifndef __I2C_HW_H
#define __I2C_HW_H

/* includes */
#include "stm32f10x.h"
#include "hw_config.h"
/* defines */
/* functions */
void HW_I2C_master_initial(void);

uint8_t HW_I2C_Read(I2C_TypeDef* I2Cx, uint8_t DeviceAddr, uint8_t RegisterAddr, uint16_t NumByteToRead, uint8_t* pBuffer);
uint8_t HW_I2C_Write(I2C_TypeDef* I2Cx, uint8_t DeviceAddr, uint8_t RegisterAddr, uint16_t NumByteToWrite, uint8_t* pBuffer);
uint8_t I2C_Check_SlaveAddr(I2C_TypeDef* I2Cx, uint8_t DeviceAddr);

uint8_t HW_I2C_UTIL_Write(I2C_TypeDef* I2Cx, uint8_t DeviceAddr, uint8_t RegisterAddr, uint8_t pBuffer);
uint8_t HW_I2C_UTIL_Read(I2C_TypeDef* I2Cx, uint8_t DeviceAddr, uint8_t RegisterAddr);
void HW_I2C_UTIL_Write_Multi(I2C_TypeDef* I2Cx, uint8_t DeviceAddr, uint8_t RegisterAddr, uint16_t NumByteToWrite, uint8_t* pBuffer);
uint8_t HW_I2C_UTIL_Read_Multi(I2C_TypeDef* I2Cx, uint8_t DeviceAddr, uint8_t RegisterAddr, uint8_t ReadCount, uint8_t (*pReadData));
uint8_t HW_I2C_UTIL_Check_SlaveAddr(I2C_TypeDef* I2Cx);

#endif  /* __I2C_HW_H */

 

# i2c_hw.c

#include "i2c_hw.h"

#define MAX_COMMUNICATION_FREQ   ((uint32_t) 400000)	// 100khz
#define FLAG_TIMEOUT             ((uint32_t)0x1000)
#define LONG_TIMEOUT             ((uint32_t)(10 * FLAG_TIMEOUT))

#define GPIO_I2C_HW        GPIOB

#define GPIO_I2C1_SCL	GPIO_Pin_6
#define GPIO_I2C1_SDA	GPIO_Pin_7
#define GPIO_I2C2_SCL	GPIO_Pin_10
#define GPIO_I2C2_SDA	GPIO_Pin_11

__IO uint32_t  UTIL_Timeout = LONG_TIMEOUT;
__IO uint16_t  UTIL_Address = 0;

void HW_I2C_master_initial(void)
{
	I2C_InitTypeDef 	I2C_InitStructure;
	GPIO_InitTypeDef	GPIO_InitStructure;

	// I2C_SCL_GPIO_CLK and I2C_SDA_GPIO_CLK Periph clock enable
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
	// I2C Periph clock enable
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C2, ENABLE);

	// Configure I2C pins: SCL , SDA
	GPIO_InitStructure.GPIO_Pin = GPIO_I2C1_SCL | GPIO_I2C1_SDA | GPIO_I2C2_SCL | GPIO_I2C2_SDA;;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;
	GPIO_Init(GPIO_I2C_HW, &GPIO_InitStructure);

	// Free all used resources
	I2C_DeInit(I2C1);
	I2C_DeInit(I2C2);

	I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
	I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;
	I2C_InitStructure.I2C_OwnAddress1 = 0x00;
	I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
	I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
	I2C_InitStructure.I2C_ClockSpeed = MAX_COMMUNICATION_FREQ;
	I2C_Init(I2C1, &I2C_InitStructure);
	I2C_Init(I2C2, &I2C_InitStructure);

	I2C_Cmd(I2C1, ENABLE);
	I2C_Cmd(I2C2, ENABLE);
}

uint8_t HW_I2C_Read(I2C_TypeDef* I2Cx, uint8_t DeviceAddr, uint8_t RegisterAddr, uint16_t NumByteToRead, uint8_t* pBuffer)
{
  __IO uint32_t UTIL_Timeout = LONG_TIMEOUT;
  __IO uint32_t temp;

  (void)(temp);

restart:

  UTIL_Timeout = LONG_TIMEOUT;
/* Send START condition */
  I2C_GenerateSTART(I2Cx, ENABLE);
  /* Test on EV5 and clear it */
  while (!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_MODE_SELECT))
  {
    if (UTIL_Timeout-- == 0)
      return ERROR;
  }

  UTIL_Timeout = LONG_TIMEOUT;
  /* Send slave address for read */
  I2C_Send7bitAddress(I2Cx, DeviceAddr, I2C_Direction_Transmitter);

  while (!I2C_CheckEvent(I2Cx,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED))
  {
    if (UTIL_Timeout-- == 0)
    {
      I2C_ClearFlag(I2Cx,I2C_FLAG_BUSY|I2C_FLAG_AF);
      goto restart;
    }
  }
  /* Clear EV6 by setting again the PE bit */
  I2C_Cmd(I2Cx, ENABLE);

  I2C_SendData(I2Cx, RegisterAddr);

  /* Test on EV8 and clear it */
  UTIL_Timeout = LONG_TIMEOUT;
  while (!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_TRANSMITTED))
  {
    if (UTIL_Timeout-- == 0)
     return ERROR;
  }

  if (NumByteToRead == 0x01)
  {
    restart3:
    /* Send START condition */
    I2C_GenerateSTART(I2Cx, ENABLE);
    while (!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_MODE_SELECT));
    /* Send Slave address for read */
    I2C_Send7bitAddress(I2Cx, DeviceAddr, I2C_Direction_Receiver);
    /* Wait until ADDR is set */
    UTIL_Timeout = LONG_TIMEOUT;
    while (!I2C_GetFlagStatus(I2Cx, I2C_FLAG_ADDR))
    {
      if (UTIL_Timeout-- == 0)
      {
        I2C_ClearFlag(I2Cx,I2C_FLAG_BUSY|I2C_FLAG_AF);
        goto restart3;
      }
    }
    /* Clear ACK */
    I2C_AcknowledgeConfig(I2Cx, DISABLE);
    __disable_irq();
    /* Clear ADDR flag */
    temp = I2Cx->SR2;
    /* Program the STOP */
    I2C_GenerateSTOP(I2Cx, ENABLE);
    __enable_irq();
    while ((I2C_GetLastEvent(I2Cx) & 0x0040) != 0x000040); /* Poll on RxNE */
    /* Read the data */
    *pBuffer = I2C_ReceiveData(I2Cx);
    /* Make sure that the STOP bit is cleared by Hardware before CR1 write access */
    while ((I2Cx->CR1&0x200) == 0x200);
    /* Enable Acknowledgement to be ready for another reception */
    I2C_AcknowledgeConfig(I2Cx, ENABLE);

    return SUCCESS;
  }
  else
    if(NumByteToRead == 0x02)
    {
      restart4:
      /* Send START condition */
      I2C_GenerateSTART(I2Cx, ENABLE);
      while (!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_MODE_SELECT));
      /* Send EEPROM address for read */
      I2C_Send7bitAddress(I2Cx, DeviceAddr, I2C_Direction_Receiver);
      I2Cx->CR1 = 0xC01; /* ACK=1; POS =1 */
      UTIL_Timeout = LONG_TIMEOUT;
      while (!I2C_GetFlagStatus(I2Cx, I2C_FLAG_ADDR))
      {
        if (UTIL_Timeout-- == 0)
        {
          I2C_ClearFlag(I2Cx,I2C_FLAG_BUSY|I2C_FLAG_AF);
          goto restart4;
        }
      }
      __disable_irq();
      /* Clear ADDR */
      temp = I2Cx->SR2;
      /* Disable ACK */
      I2C_AcknowledgeConfig(I2Cx, DISABLE);
      __enable_irq();
      while ((I2C_GetLastEvent(I2Cx) & 0x0004) != 0x00004); /* Poll on BTF */

       __disable_irq();
      /* Program the STOP */
      I2C_GenerateSTOP(I2Cx, ENABLE);
      /* Read first data */
      *pBuffer = I2Cx->DR;
      pBuffer++;
      /* Read second data */
      *pBuffer = I2Cx->DR;
      __enable_irq();
      I2Cx->CR1 = 0x0401; /* POS = 0, ACK = 1, PE = 1 */

      return SUCCESS;
    }
  else
  {
restart2:
    UTIL_Timeout = LONG_TIMEOUT;
    /* Send START condition */
    I2C_GenerateSTART(I2Cx, ENABLE);
    /* Test on EV5 and clear it */
    while (!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_MODE_SELECT))
    {
      if (UTIL_Timeout-- == 0) return ERROR;
    }
    UTIL_Timeout = LONG_TIMEOUT;
    /* Send slave address for read */
    I2C_Send7bitAddress(I2Cx,  DeviceAddr, I2C_Direction_Receiver);
    while (!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED))
    {

      if (UTIL_Timeout-- == 0)
      {
        I2C_ClearFlag(I2Cx,I2C_FLAG_BUSY|I2C_FLAG_AF);
        goto restart2;
      }
    }

    /* While there is data to be read; here the safe procedure is implemented */
    while (NumByteToRead)
    {

      if (NumByteToRead != 3) /* Receive bytes from first byte until byte N-3 */
      {
        while ((I2C_GetLastEvent(I2Cx) & 0x00004) != 0x000004); /* Poll on BTF */
        /* Read data */
        *pBuffer = I2C_ReceiveData(I2Cx);
        pBuffer++;
        /* Decrement the read bytes counter */
        NumByteToRead--;
      }

      if (NumByteToRead == 3)  /* it remains to read three data: data N-2, data N-1, Data N */
      {

        /* Data N-2 in DR and data N -1 in shift register */
        while ((I2C_GetLastEvent(I2Cx) & 0x000004) != 0x0000004); /* Poll on BTF */
        /* Clear ACK */
        I2C_AcknowledgeConfig(I2Cx, DISABLE);
        __disable_irq();
        /* Read Data N-2 */
        *pBuffer = I2C_ReceiveData(I2Cx);
        pBuffer++;
        /* Program the STOP */
        I2C_GenerateSTOP(I2Cx, ENABLE);
        /* Read DataN-1 */
        *pBuffer = I2C_ReceiveData(I2Cx);
        __enable_irq();
        pBuffer++;
        while ((I2C_GetLastEvent(I2Cx) & 0x00000040) != 0x0000040); /* Poll on RxNE */
        /* Read DataN */
        *pBuffer = I2Cx->DR;
        /* Reset the number of bytes to be read by master */
        NumByteToRead = 0;
      }
    }
    /* Make sure that the STOP bit is cleared by Hardware before CR1 write access */
    while ((I2Cx->CR1&0x200) == 0x200);
    /* Enable Acknowledgement to be ready for another reception */
    I2C_AcknowledgeConfig(I2Cx, ENABLE);

    return SUCCESS;
  }
}

uint8_t HW_I2C_Write(I2C_TypeDef* I2Cx, uint8_t DeviceAddr, uint8_t RegisterAddr,
                               uint16_t NumByteToWrite,
                               uint8_t* pBuffer)
{

 restart1:
  UTIL_Timeout = LONG_TIMEOUT;
  /* Send START condition */
  I2C_GenerateSTART(I2Cx, ENABLE);
  /* Test on EV5 and clear it */
  while (!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_MODE_SELECT))
  {
    if (UTIL_Timeout-- == 0) return ERROR;
  }
  /* Send slave address for write */
  I2C_Send7bitAddress(I2Cx, DeviceAddr, I2C_Direction_Transmitter);

  UTIL_Timeout = LONG_TIMEOUT;
  /* Test on EV6 and clear it */
  while (!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED))
  {

    if (UTIL_Timeout-- == 0)
    {
      I2C_ClearFlag(I2Cx,I2C_FLAG_BUSY|I2C_FLAG_AF);
      goto restart1;
    }
  }

  UTIL_Timeout = LONG_TIMEOUT;

  /* Transmit the first address for r/w operations */
  I2C_SendData(I2Cx, RegisterAddr);

  /* Test on EV8 and clear it */
  while (!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_TRANSMITTED))
  {
    if (UTIL_Timeout-- == 0)
      return ERROR;
  }
  if (NumByteToWrite == 0x01)
  {
    UTIL_Timeout = LONG_TIMEOUT;
    /* Prepare the register value to be sent */
    I2C_SendData(I2Cx, *pBuffer);

    /* Test on EV8 and clear it */
    while (!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_TRANSMITTED))
    {
      if (UTIL_Timeout-- == 0)
        return ERROR;
    }

    /* End the configuration sequence */
    I2C_GenerateSTOP(I2Cx, ENABLE);
    return SUCCESS;
  }
  I2C_SendData(I2Cx, *pBuffer);
  pBuffer++;
  NumByteToWrite--;
  /* While there is data to be written */
  while (NumByteToWrite--)
  {
    while ((I2C_GetLastEvent(I2Cx) & 0x04) != 0x04);  /* Poll on BTF */
    /* Send the current byte */
    I2C_SendData(I2Cx, *pBuffer);
    /* Point to the next byte to be written */
    pBuffer++;

  }
  UTIL_Timeout = LONG_TIMEOUT;
  /* Test on EV8_2 and clear it, BTF = TxE = 1, DR and shift registers are
   empty */
  while (!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_TRANSMITTED))
  {
    if (UTIL_Timeout-- == 0) return ERROR;
  }
  /* Send STOP condition */
  I2C_GenerateSTOP(I2Cx, ENABLE);
  return SUCCESS;
}

uint8_t I2C_Check_SlaveAddr(I2C_TypeDef* I2Cx, uint8_t DeviceAddr)
{
	uint8_t   returnack = SUCCESS;

	UTIL_Timeout = FLAG_TIMEOUT;
	/* Send START condition */
	I2C_GenerateSTART(I2Cx, ENABLE);
	/* Test on EV5 and clear it */
	while (!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_MODE_SELECT))
	{
		if (UTIL_Timeout-- == 0) return ERROR;
	}
	/* Send slave address for write */
	I2C_Send7bitAddress(I2Cx, DeviceAddr, I2C_Direction_Transmitter);

	UTIL_Timeout = FLAG_TIMEOUT;
	/* Test on EV6 and clear it */
	while (!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED))
	{

		if (UTIL_Timeout-- == 0)
		{
		  I2C_ClearFlag(I2Cx,I2C_FLAG_BUSY|I2C_FLAG_AF);
		  returnack = ERROR;
		  break;
		}
	}
	I2C_GenerateSTOP(I2Cx, ENABLE);

	return returnack;
}

uint8_t HW_I2C_UTIL_Write(I2C_TypeDef* I2Cx, uint8_t DeviceAddr, uint8_t RegisterAddr, uint8_t pBuffer)
{
	return HW_I2C_Write(I2Cx, DeviceAddr<<1,RegisterAddr,1,&pBuffer);
}

uint8_t HW_I2C_UTIL_Read(I2C_TypeDef* I2Cx, uint8_t DeviceAddr, uint8_t RegisterAddr)
{
	uint8_t	pBuffer;

	HW_I2C_Read(I2Cx, DeviceAddr<<1,RegisterAddr,1,&pBuffer);

	return pBuffer;
}

void HW_I2C_UTIL_Write_Multi(I2C_TypeDef* I2Cx, uint8_t DeviceAddr, uint8_t RegisterAddr, uint16_t NumByteToWrite, uint8_t* pBuffer)
{
	HW_I2C_Write(I2Cx, DeviceAddr<<1,RegisterAddr,NumByteToWrite,pBuffer);
}

uint8_t HW_I2C_UTIL_Read_Multi(I2C_TypeDef* I2Cx, uint8_t DeviceAddr, uint8_t RegisterAddr, uint8_t ReadCount, uint8_t (*pReadData))
{
	HW_I2C_Read(I2Cx, DeviceAddr<<1,RegisterAddr,ReadCount,pReadData);

	return 1;
}

uint8_t HW_I2C_UTIL_Check_SlaveAddr(I2C_TypeDef* I2Cx)
{
	uint8_t i = 0x00;

	for(i = 0; i < 255; i++)
	{
		if(I2C_Check_SlaveAddr(I2Cx, i) == SUCCESS)
		{
			return i;
		}
	}
	return i;
}
반응형

+ Recent posts