'Embedded Lab/ARM'에 해당되는 글 4건

  1. 2014.03.05 [STM32 : SPI, using chip select2]
  2. 2014.03.05 [STM32 : SPI, using chip select]
  3. 2013.03.22 [SWI의 진실]
  4. 2013.03.20 [논리 스프트와 산술 시프트의 차이]

이번에 고생 했던 EEPROM M95512 이제는 잘 동작 한다~

 

#define WRSR  0x01 //Write Status Register
#define WRITE 0x02 //Write to Memory Array 
#define READ  0x03 //Read from Memory Array
#define WRDI  0x04 //Write Disable
#define RDSR  0x05 //Read Status Register
#define WREN  0x06 //Write Enable
#define DUMMY 0x00 //DUMMY BYTE
  
#define EEPROM_CS_LOW()  GPIO_ResetBits(GPIOB, GPIO_Pin_0);
#define EEPROM_CS_HIGH()  GPIO_SetBits(GPIOB, GPIO_Pin_0);

void SPI_Config(void);
uint8_t SPI_SendByte(uint8_t Data);
uint8_t SPI_Flash_Read(uint16_t address);
void SPI_Flash_Write(uint16_t address, uint8_t data);

 

 

/* Includes ------------------------------------------------------------------*/
#include "stdio.h"
#include "stm32f10x.h"
#include "M95512.h"

void SPI_Config(void)
{
  SPI_InitTypeDef SPI_InitStructure;
  GPIO_InitTypeDef GPIO_InitStructure;

  SPI_Cmd(SPI1, DISABLE); 
  SPI_I2S_DeInit(SPI1);
  
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1 | RCC_APB2Periph_AFIO, DISABLE); 
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
  GPIO_Init(GPIOA, &GPIO_InitStructure);

  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
  GPIO_Init(GPIOA, &GPIO_InitStructure);

  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;
  GPIO_Init(GPIOA, &GPIO_InitStructure); 
      
  /* Enable SPI clock, SPI1 */ 
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_SPI1, ENABLE);
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; // 50 MHz
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  GPIO_Init(GPIOA, &GPIO_InitStructure);
  
  // Configure CS pin as output floating
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
  GPIO_Init(GPIOB, &GPIO_InitStructure);

  /* SPI configuration -------------------------------------------------------*/
  EEPROM_CS_HIGH();
  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_Soft;
  SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_8;
  SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
  SPI_InitStructure.SPI_CRCPolynomial = 7;
  SPI_Init(SPI1, &SPI_InitStructure);
  SPI_Cmd(SPI1, ENABLE); 
}

uint8_t SPI_SendByte(uint8_t Data)
{
  while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);
  SPI_I2S_SendData(SPI1, Data); 
  while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET);
  return SPI_I2S_ReceiveData(SPI1);
}


static void M95512_WREN(void)
{//0x06 Write Enable
  EEPROM_CS_LOW(); 
  SPI_SendByte(WREN); 
  EEPROM_CS_HIGH();
}

static void M95512_WRDI(void)
{//0x04 Write Disable
  EEPROM_CS_LOW(); 
  SPI_SendByte(WRDI); 
  EEPROM_CS_HIGH();
}

static void M95512_RDSR(void)
{//0x05 Read Status Register
  unsigned char data_H, data_L;
  unsigned int data = 0;
  
  EEPROM_CS_LOW();  
  SPI_SendByte(RDSR); 
//  data_H = SPI_ReadByte();  
//  data_L = SPI_ReadByte();
  EEPROM_CS_HIGH();
  data = (data_H << 1) + (data_L << 7);     
}

static void M95512_WRSR(unsigned char reg)
{//0x01 Write Status Register
  EEPROM_CS_LOW();  
  SPI_SendByte(WRSR);
  SPI_SendByte(reg);  
  EEPROM_CS_HIGH(); 
}

uint8_t SPI_Flash_Read(uint16_t address)
{
  uint8_t data;
  
   EEPROM_CS_LOW();
  SPI_SendByte(READ);
  SPI_SendByte((address & 0xFF00) >> 8);
  SPI_SendByte(address & 0xFF);
  data = SPI_SendByte(DUMMY);
  EEPROM_CS_HIGH();
  return data;

   
void SPI_Flash_Write(uint16_t address, uint8_t data)
{
  M95512_WREN();
 
  EEPROM_CS_LOW();
  SPI_SendByte(WRITE);          // Send SPI instruction 
  SPI_SendByte((address & 0xFF00) >> 8);  // Send SPI address MSB
  SPI_SendByte(address & 0xFF);           // Send SPI address LSB
  SPI_SendByte(data);           // Send SPI Write data(Byte)
  EEPROM_CS_HIGH();
}

 

위와 같이 하여 놓고

main에서

  SPI_Flash_Write(0x0000,0x11);
  SPI1_READ_DATA = SPI_Flash_Read(0x0000);

사용하면 데이타가 잘 들어 온다~

'Embedded Lab > ARM' 카테고리의 다른 글

[STM32 : SPI, using chip select]  (0) 2014.03.05
[SWI의 진실]  (0) 2013.03.22
[논리 스프트와 산술 시프트의 차이]  (0) 2013.03.20
Posted by cyj4369
,
int main(void)
{
 char Received_From_device[500] = "";        // Maximum data from device of 500 bytes
 //char character[10] = "";
    char ETX_character;
 int i,a,lazy_timeout_counter,lazy_timeout_max,tmp,adc_value;
 char c;
  
  RCC_Configuration();
  
  GPIO_Configuration();
 
  SPI2_Configuration();   //SPI configure
  
  USART1_Configuration();
 
   GPIO_SetBits(GPIOB, GPIO_Pin_12);   //set Chip Select HIGH for SPI
  
 while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET); // Wait for Empty
  
    USART_SendData(USART1, 0x49); // Send 'I'
 while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
 USART_SendData(USART1, 0x42); // Send 'B'
SPI_Loop:
 Delay(1000);    //1second delay
 
 //goto Jump2Here;
 
 //Select CH0 of LTC2492
 
 GPIO_ResetBits(GPIOB, GPIO_Pin_12); // Assert -CS
 Delay_us(10); // overkill
 
// You need semicolons after the whiles otherwise they repeat the next statement
 
 while(SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE) == 0); //wait for transmit buffer to be empty, should be
 
 SPI_I2S_ReceiveData(SPI2); // Clear RXNE
 SPI_I2S_SendData(SPI2, LTC_Internal_Temperature_select); //LTC_Internal_Temperature_select
 while(SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE) == 0); //wait for transmit buffer to not be empty (ie data loaded in)
 SPI_I2S_SendData(SPI2, 0); // Fill for 32-bits, remaining 16-bits in holding buffer
 
 while(SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE) == 0); // wait for last bit to be sent
 SPI_I2S_ReceiveData(SPI2); // Clear RXNE, first word
 while(SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE) == 0); // wait for last bit to be sent
 SPI_I2S_ReceiveData(SPI2); // Clear RXNE, second word
 
 Delay_us(10);
 GPIO_SetBits(GPIOB, GPIO_Pin_12); // Release -CS
 
 
 Delay(1000);    //1second delay
 
 
 //await result readable via SPI and read in result via SPI   two 16bit reads over SPI
 
 GPIO_ResetBits(GPIOB, GPIO_Pin_12); // Assert -CS
 Delay_us(10); // overkill
 
 while(SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE) == 0); // should be empty
 
 SPI_I2S_ReceiveData(SPI2);  // clear RXNE
 SPI_I2S_SendData(SPI2, LTC_Internal_Temperature_select); // send command word
 while(SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE) == 0); //wait for transmit buffer to not be empty (ie data loaded in)
 SPI_I2S_SendData(SPI2, 0); // Fill for 32-bits, remaining 16-bits in holding buffer
 while(SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE) == 0);
 tmp = SPI_I2S_ReceiveData(SPI2);  // read word from receive buffer, high order 16-bits
 adc_value =  tmp * 65536;
 while(SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE) == 0);  // wait until receive buffer is not empty
 tmp = SPI_I2S_ReceiveData(SPI2);  // read word from receive buffer, low order 16-bits
 adc_value = adc_value + tmp;
 
 Delay_us(10);
 GPIO_SetBits(GPIOB, GPIO_Pin_12); // Release -CS
 
  
 
  
 
Jump2Here:
 //send result via RS232
 
 while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
 USART_SendData(USART1, 0x43); // Send 'C'
 while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
 USART_SendData(USART1, 0x48); // Send 'H'
 while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
 USART_SendData(USART1, 0x30); // Send '0'
 while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
 USART_SendData(USART1, 0x3A); // Send ':'
 
 // Sends as binary, not ascii
 //adc_value = 1234567890;
while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
 USART_SendData(USART1, ((adc_value >> 24) & 0xFF));
while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
 USART_SendData(USART1, ((adc_value >> 16) & 0xFF));
while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
 USART_SendData(USART1, ((adc_value >>  8) & 0xFF));
while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
 USART_SendData(USART1, ((adc_value >>  0) & 0xFF));
 
 //goto SPI_Loop;
 
 while (1);
}


'Embedded Lab > ARM' 카테고리의 다른 글

[STM32 : SPI, using chip select2]  (0) 2014.03.05
[SWI의 진실]  (0) 2013.03.22
[논리 스프트와 산술 시프트의 차이]  (0) 2013.03.20
Posted by cyj4369
,

[SWI의 진실]

Embedded Lab/ARM 2013. 3. 22. 19:53

Exception Handler를 다루다 보니, 궁금한 게 생겼어요. Hardware없이 interrupt를 거는 방법이 있을까요? SoftWare Interrupt라는 거 앞에서부터 언급되었었는데, Interrupt는 Asynchronous하게 암때나 걸리는 게 Interrupt일진데, Software로 어떻게 암때나 interrupt를 건다는 얘길까요. 실은 Software Interrupt라는 건 Interrupt가 아니에요. 실은 Software적으로 Exception을 걸 수 있는 걸 말하는 거죠. Software적으로 Exception을 걸게 되면 보통 User mode에 있던 System이 Supervisor mode로 전환이 되고요, Software Interrupt를 거는 순간부터는 Privileged Mode로 전환되는 거니까, System을 마음대로 주무를 수 있는 권한이 생기는 거죠. 
 
왜 이런 SWI를 굳이 사용하는 걸까요? compatibility때문에 사용하게 되는 경우가 많습니다. 보통은 kernel service를 이용할 때 많이 사용되는데요, 이렇게 하면 좋은 점이 말이죠, 일단은 Privileged mode로 들어갈 수 있게 되고, Kernel service로 들어서는 입구가 하나로 한정이 되므로 Kernel 입장에서는 SWI 부분만 수정을 잘하면 되는 장점이 있지요. 이런걸 유식한 말로 compatibility라고 합니다. 냐하하. 
 
SWI가 이용되는 대표적인 예는 아래의 두 가지에요. 
1. System Call (Kernel)
2. Semi hosting
 
System Call이 보통 Kernel등에서 많이 사용되는 개념인데, Kernel은 SVC mode에서 동작하고, 일반 application은 User Mode에서 동작하기 때문에, User Mode의 일반 application이 Kernel에게 service를 요청할 때 사용하지요. SWI를 걸어서 Kernel Mode로 System mode를 바꾸는 거죠 뭐. 
 
그리고, Semi hosting이라는 건 Target에서 I/O에 관련된 것들을 경로를 바꾸어 Target에서 실행되어야 하는 I/O를 Debugger를 실행하고 있는 Host system에서 대신 수행하게 하는 것인데, 예를 들면 UART로 Message를 뿌리던 target의 routine을 Semi hosting routine으로 갈아치우면, UART가 아닌 Debugger로 target의 Reporting을 직접 받을 수 있는 장점이 있어요. 이런 Semi hosting에 관련된 자세한 내용은 How to Debug section에서 다시 자세히 기술할 예정이오니, 여기서는 concept만 잘 가져가시도록 하시죠. 
 
그러면, SWI는 어떻게 구현되고, 어떻게 Handler를 구현하게 되는 걸까 하는 문제에 focusing을 해보는 게 어떨까 생각 중입니다. 
 
Software Interrupt를 걸려면 어떻게 해야 할까요? 간단하죠. 
SWI {condition}
이렇게 assembly를 삽입해 주면 SWI 명령어를 만나는 순간 Exception은 발생하고, SWI Exception Vector (0x0008)번지로 branch하게 됩니다. 이렇게 SWI 명령어 자체로 Exception을 걸어 User mode에서 강제로 SVC mode로 갈 수 있다니 이 얼마나 시적인 일입니꺄.
 
SWI {condition} 이라고 했는데, 그러면 SWI에 대해서 여러 가지 종류의 SWI를 걸 수 있다는 말인데요, 즉 슨 SWI 뒤에 숫자를 적어 넣고, 막상 Handler에서 뒤에 parameter로 준 condition을 switch 걸어서 여러 가지 case를 처리할 수 있다는 말이기도 하지요. 
 
그런데, ARM에서는 Exception이 발생하고 나면, Exception Vector로 jump해서 곧바로 Handler로 branch한다고 보았었는데, 어떻게 parameter를 준다는 말입니까. 이거야 말로 귀신이 곡할 노릇노릇 노른자이네요. 이것이야 말로 System Software를 하는 사람들의 실력이 빛을 발하는 순간이에요. 
 
모든 것은 원하는 것이 있으면 통하는 법이죠. 그것의 비밀은 SWI 명령자체가 비밀입니다. SWI 명령어의 32bit binary 형태를 한번 볼까요?
 
 
 
32bit 명령어 중 MSB 4bit는 조건을 나타내는 명령어, 즉 EQ, NEQ 등의 뭐 그거 있었잖아요. condition flag를 보고서 어떻게 할거냐는 조건 명령 그게 4bit 들어가고요. 바로 다음에 따라오는 4bit에 연달아 1111이 있으며 SWI 명령입니다. 그러면, 뒤에 24bit가 남게 되죠. 이 24bit에 해당하는 곳에 parameter가 들어갈 수 있게 되는 거죠. 실은 버려지게 되는 내용이지만, 재활용 수준에서 이걸 가져다가 여러 가지 종류의 SWI를 거는 것처럼 만들 수 있어요. 순수하게 System Software Engineer가 구현해야 하는 몫이에요. 뒤에 붙어 있는 LSB 24bit와는 아무 상관없이 일단 1111 (SWI)가 있으면 Processor는 Exception을 발생시킵니다. 그러면, 뒤에 붙어 있던 LSB 24 bit를 어떻게 parameter로 재활용할 수 있을 까요. 자자, 생각해 봅시다. 힌트는 Software Interrupt가 걸리게 되면, R14_SVC에 돌아갈 주소가 저장된다는 사실이에요. 
 
으흐흐, 그렇죠. 돌아갈 주소를 안다는 것은 돌아갈 주소에서 한 칸만 이전을 가져올 수만 있다면 SWI가 걸린 위치를 가져올 수 있다는 말이지요. 그러면 SWI가 걸린 위치를 가져와서 LSB 24bit만 Masking해내면 요리 끝이에요. 뭐 다 이런 식인 거에요. 
 
LDR r0, [r14, #-4]
BIC r0, r0, #0xFF000000 
 
요렇게 하면 r14가 가리키는 곳에서 4를 뺀 곳의 값 자체를 읽어와서 하위 24 bit를 r0에 긁어 올 수 있겠어요. 짜란! 자자, 그러면 실제로 어떻게 Software를 짜는지 알아야 하지 않겠어요?
 
두 가지 예를 들어볼 게요.하나는 위에서 본 것과 같은 SWI 호출과 Handler의 구현입니다. 나머지 한가지는 C Level의 SWI 의 직접 호출 구현이지요. 궁금 안 하실지도 모르겠으나, 조금 살펴 보져 머. 
 
첫 번째, 일반적인 SWI 호출하는 방법을 한번 해보시지요. 
 일단 c file에서 SWI를 호출해야겠죠. SWI_OOOPS()라는 함수에서 SWI 호출해 보겠습니다.
 
 
SWI_OOOPS()
{
    .............
    SWI_Exception();
    .............
}
 
그러면, SWI Assembly 명령어를 사용하기 위하여, Assembly file 하나에서 SWI_Exception 함수를 구현해 볼까요. 아래처럼 직접 SWI에 parameter 0x121212를 줘봅시다. 
 
SWI_Exception
  SWI  0x121212
이렇게 하면   SWI  0x121212 를 만나는 순간 곧바로 Software Interrupt가 걸리게 되고 Exception Vector로 branch하게 됩니다. 
 
0x8번지에 이렇게 씌여져 있겠죠. 
b SWI_Handler
 
그러면, 이제 간단하게 C Level의 SWI Handler를 부르기 위한 Handler를 만들어 주면 됩니다. 물론 여기에서 LSB 24 bit도 건져 내야죠.
 
 
SWI_Handler
   STMFD sp!, {lr}                  ; 돌아갈 주소 저장
   LDR  r0,  [lr, #-4]                  ; SWI 주소의 값을 가져옴. 
   BIC  r0,  r0,  #0xFF000000      ; LSB 24bit 건져냄. 
   BL  SWI_C_Handler                 ; r0에 넣었으니까, AAPCS에 의하여 첫번째 argument로
   LDMFD sp!, {lr}                     ; 다 처리하고 왔으면 돌아가야지~

 

뭐 이런 Story죠.

그럼 이때! SWI_C_Handler에 잘 도달 할 수 있도록 수로를 잘 터왔으니까, SWI_C_Handler만 잘 구현하면 됩니다. 잘 보세요.

 

 

void SWI_C_Handler (int OPTion)

 
 switch(option)
 {
  case 0x123432: 
           UART_MESSAGE ("SWI 0x123432");
      break ;
  case 0x121212 :
           LCD_MESSAGE ("SWI 0x121212");
      break ;
  case 0x654321:
           USB_MESSAGE ("SWI 0x654321");
      break ;
 }
 
}
 
r0에 LSB 24 bit를 넣었으니까, 그 값은 int option으로 넘어오게 되고, 그 option에 대해서 switch를 걸었으니까 결국 LCD_MESSAGE 를 찍겠네요. 음.. 어렵지 않군요. 
 
자, 여기서 그럼 다른 종류의 LSB 24bit를 걸기 위해서 SWI_Exception() 함수를 Assembly로 따로따로 구현해야 하느냐! 조금 더 편한 방법이 있어요. 
 
함수를 SWI와 번호로 선언할 수 있어요.

 
 __swi(0x123432) void UART_OUT (void)라고 선언하고서,
 
SWI_OOOPS()
{
    .............
    SWI_Exception();
    UART_OUT();
    .............
}
 
이렇게 부르면 차례로 LCD MESSAGE와 UART MESSAGE가 실행되게 됩니다. 어떻게 해서 이런 일이 가능한 것이냐 하면, UART_OUT() 함수 자체가 SWI 0x123432으로 compile 된답니다.
결국 SWI_OOOPS()함수는
 
 
SWI_OOOPS
   ........
   SWI 0x121212
   SWI 0x123432
   .........
 
이런 식으로 컴파일 되겠죠 뭐.

출처 : http://recipes.egloos.com/5037342

'Embedded Lab > ARM' 카테고리의 다른 글

[STM32 : SPI, using chip select2]  (0) 2014.03.05
[STM32 : SPI, using chip select]  (0) 2014.03.05
[논리 스프트와 산술 시프트의 차이]  (0) 2013.03.20
Posted by cyj4369
,

논리 시프트와 산술 시프트의 차이

논리 시프트 역시 비트를 이동하는 연산이나, 산술 시프트와의 제일 큰 차이는 부호비트(sign bit)가 보존되지 않는다는 것이다. 따라서 부호가 정의된 16비트 정수(signed integer)에서 연산의 결과값이100 0000(2)=32768(10) 이상의 범위를 넘어갈 경우 부호가 바뀌는 경우가 발생한다.    

'Embedded Lab > ARM' 카테고리의 다른 글

[STM32 : SPI, using chip select2]  (0) 2014.03.05
[STM32 : SPI, using chip select]  (0) 2014.03.05
[SWI의 진실]  (0) 2013.03.22
Posted by cyj4369
,