[Tiva]startup_ccs.c 파일에 외부 인터럽트 추가하기

임베디드/TI 2014. 8. 9. 22:33

 Tiva C 기반의 MCU로 외부 인터럽트를 설정할 때 일반적으로 메인함수에서 IntRegister()와 같이 해당 인터럽트가 발생하였을 때 실행할 함수를 직접 설정하는 방법이 있습니다. 이 방법 이외에 인터럽트 함수를 등록할 수 있는 방법이 하나 존재합니다!

 프로젝트 내부에 있는 startup_ccs.c 파일에 인터럽트 함수명을 설정해두면 main() 함수에서 정의를 하지 않아도 해당 함수를 인터럽트로 바로 사용하실 수 있습니다.



프로젝트에서 startup_ccs.c 파일을 열어보면 다음과 같은 함수들을 확인하실 수 있습니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include <stdint.h>
#include "inc/hw_nvic.h"
#include "inc/hw_types.h"
 
extern void Timer0IntHandler(void);
extern void Timer1IntHandler(void);
 
#pragma DATA_SECTION(g_pfnVectors, ".intvecs")
void (* const g_pfnVectors[])(void) =
{
    (void (*)(void))((uint32_t)&__STACK_TOP),
                                            // The initial stack pointer
    ResetISR,                               // The reset handler
    NmiSR,                                  // The NMI handler
    FaultISR,                               // The hard fault handler
    //--------코드 생략--------//
    Timer0IntHandler,                       // Timer 0 subtimer A
    IntDefaultHandler,                      // Timer 0 subtimer B
    Timer1IntHandler,                       // Timer 1 subtimer A
    IntDefaultHandler,                      // Timer 1 subtimer B
    IntDefaultHandler,                      // Timer 2 subtimer A
    IntDefaultHandler,                      // Timer 2 subtimer B
    //--------코드 생략--------//
    IntDefaultHandler,                      // PWM 1 Generator 0
    IntDefaultHandler,                      // PWM 1 Generator 1
    IntDefaultHandler,                      // PWM 1 Generator 2
    IntDefaultHandler,                      // PWM 1 Generator 3
    IntDefaultHandler                       // PWM 1 Fault
};


위의 함수에서 extern void는 사용하게 될 인터럽트의 명칭들입니다.

그리고 아래는 등록하고자 하는 코드들의 모임입니다.


extern void로 Timer0IntHandler()와 Time1IntHandler() 함수를 다음과 같이 입력한 후

아래 주석 부분에 자신이 해당 코드를 실행하고자 하는 인터럽트 부분에 함수명을 적어주면 됩니다.


이 과정을 거치신 후 프로그램을 실행하시면 인터럽트가 원활하게 동작되는 것을 확인하실 수 있습니다.

300x250

진동모터 연결선이 빠졌을 때 대처법

임베디드 2014. 8. 8. 23:33

 열심히 작동하던 진동모터가 지속되던 진동으로 인해 연결선 끝부분이 쏙 하고 빠져버리는 대참사가 벌어졌습니다.

 처음에는 어떻게 해야할지 잠시 당황했으나 다시 대처 방법을 공부한 후 이를 고쳐보기로 하였습니다.


보시는 대로 진동모터의 끝부분이 참혹하게 빠져버렸습니다.

그나미 끝 부분에 빠져나간 선의 일부가 약간이나마 남아서 다시 연결 할 수 있을 듯 합니다.



우선 잘려나간 부분의 끝을 칼로 살살 도려냅니다.

계속 까다보면 잘려나간 틈으로 전선이 살짝 남는 것을 보실 수 있습니다.



까진 부분에 잽싸게 선을 연결한 후 납으로 때워버립니다.



드디어 성공!



끝부분이 다시 떨어지지 않도록 글루건으로 완전히 고정시켜 버립니다.



조금 멋이 떨어지지만 아무튼 동작이 잘 되는 것으로 보아 성공한 듯 합니다.

다음은 이러한 참사가 다시 벌어지지 않도록 진동모터 끝부분을 확실히 마무리 하는 작업에 들어갑니다.



진동모터를 고정시킬 PCB판을 잘라냅니다.

휘어지는 PCB판을 사용하시면 좀 더 유연하게 사용하실 수 있습니다.



PCB판에 진동모터 끝부분을 납땜합니다.



이로서 진동모터의 짫은 선 문제는 해결되었습니다.


글루건으로 납땜한 부분을 마무리하면 어떤 상황에서도 진동모터를 무사히(?) 사용하실 수 있습니다!

300x250

파워서플라이로 모듈 사용시 주의사항

임베디드 2014. 8. 2. 12:41

 매번 파워서플라이를 만지면서도 아차 하는 실수로 모듈 하나가 타버리는 실수를 해버렸습니다. 파워서플라이를 옮기던 중 눈금이 돌아가 있던 듯 한데 수치를 보지 않고 그냥 모듈에 연결해 버린것이 화근이었던 듯 합니다.




 이렇게 모듈이 타버려 두 번 다시 사용할 수 없는 상황이 되어버린다면 정말 마음아프지 않을 수 없습니다. 특히 고가격의 모듈이라면 스트레스가 상당할 겁니다.


 임베디드 분야를 공부하시는 분들이라면 매우 기본적인 상식이기도 하지만 순간의 실수로 비싼 모듈을 망가뜨릴 위험이 있습니다. 원숭이도 나무에서 떨어질 때가 있듯이 말이지요. 파워서플라이를 사용할 때 마다 다음과 같은 수칙을 확인하고 사용하도록 합시다.


 1. 파워서플라이를 켜기 전 가급적이면 모듈과 분리시킨 후 키도록 합니다.

 2. 모듈에 파워서플라이를 연결하기 전, 파워서플라이가 해당 모듈의 정격전압에 맞는지 확인합니다.

 3. 모듈에서 이상이 발생시 즉시 파워서플라이로부터 모듈을 떼어내 버립니다.

 4. 파워서플라이를 사용 후 반드시 전원을 끄도록 합니다.

300x250

[Tiva] I2CMasterSlaveAddrSet()

임베디드/TI 2014. 8. 1. 21:02

I2CMasterSlaveAddrSet(uint32_t ui32Base, uint8_t ui8SlaveAddr, bool bReceive)


 이 함수는 MCU가 I2C 통신을 개시하기 전에 통신할 Slave의 주소값을 설정한 후 통신을 개시할 때 쓰는 함수이다.


uint32_t ui32Base

첫 번째 인자는 I2C 통신을 하게 될 Master 의 Base Address이다.


uint8_t ui8SlaveAddr

두 번째 인자는 I2C 통신시 전달할 Slave의 Address이다. 이 때 Slave의 Address값은 7bit값이어야 한다.

시중에 있는 I2C 통신의 DataSheet에서 설정되어 있는 주소는 일반적으로 8비트로 구성되어있는데

이는 해당 8비트 주소의 오른쪽 끝부분이 R/S를 설정하는 부분이기 때문이다.

DataSheet에 설정된 Address를 사용할 경우 실제 Slave의 Address를 오른쪽으로 비트이동을 하면 된다. 간단하게 ui8SlaveAddr / 2를 하면 쉽게 적용할 수 있다.


bool bReceive

세 번째 인자는 I2C 통신시 Slave에게 하고자 하는 R/S를 설정합니다.

true - R(Slave로부터 데이터를 읽어옵니다.)

false - S(Slave에 값을 저장합니다.)



다음은 해당 함수를 적용한 소스코드와 결과이다.


ROM_I2CMasterSlaveAddrSet(I2C0_BASE, 0xE0 / 2, false);

ROM_I2CMasterDataPut(I2C0_BASE, 0x7E);

ROM_I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_SINGLE_SEND);


while (ROM_I2CMasterBusy(I2C0_BASE)) {


}




① : SLAVE의 ADDRESS 주소

② : R/S

③ : SLAVE의 ACK

④ : R의 경우 = Master가 Slave로부터 전달되는 값을 읽음

S의 경우 = Master가 Slave에게 값을 전달함

⑤ : Master의 ACK


300x250

[Tiva] TM4C의 I2C 통신 파형 보는 방법

임베디드/TI 2014. 7. 28. 21:50

 I2C 통신을 처음 입문하는 분들은 종종 파형의 원리를 깨닫지 못해 많이 해메는 경우가 많습니다. 코드 상으로는 감이 오지 않는 I2C 통신을 오실로스코프를 통해 파형을 확인해보면 그 원리를 쉽게 알 수 있습니다.




 위 사진은 오실로스코프에 찍은 I2C 통신중인 파형이고 노란색은 SDA, 파란색은 SCL입니다. 아래는 I2C 회로를 설계하는데 참고할 수 있는 데이터시트의 파형입니다.


 위 사진의 파형을 쉽게 구분할 수 있게 7단계로 나누었고 그에 대한 각각의 부분은 다음과 같이 설명할 수 있습니다.


① : START

SCL이 HIGH 상태일 때 SDA가 HIGH에서  LOW로 변하는 것으로 I2C 통신을 개시합니다.


② : Slave address

Master가 통신하기 원하는 Salve address 주소를 전송합니다. 1번째부터 7번째 SCL의 edge 클록에서의 7비트가 Slave Address 주소입니다.


③ : R/S

Master가 Salve 에서 할 동작을 설정합니다. HIGH일 때는 Slave로부터 데이터를 전달받고 LOW일 때는 Slave에 데이터를 전송합니다.


④ : ACK

Slave가 Master에게 데이터를 제대로 전송하였음을 확인하는 신호입니다. Slave가 데이터를 완벽히 수신하였을 때 SDA의 값을 LOW로 끌어내려 SCL에 edge 클록이 들어올 때 까지 고정시키다가 값이 제대로 전달되면 SDA를 놓아줍니다다.


⑤ : DATA

R/S에서 설정 대로 데이터를 보내거나 받는다. 데이터 값은 8비트입니다.


⑥ : ACK

Master가 Slave에게 보내는 ACK 신호입니다.


⑦ : STOP

SCL이 HIGH 상태일 때 SDA가 LOW에서 HIGH로 변하는 것으로 I2C 통신을 종료합니다.


300x250

MCU 입력으로 설정한 핀의 값이 일정하지 않을 때(Floating)

임베디드/MCU 2014. 7. 27. 16:40

 MCU를 설계할 때 많은 빈도로 사용되는 기능 중 하나는 아마 GPIO(General Purpose Input Output)일 겁니다. 거의 모든 MCU 설계의 기본이기도 하지요.


 MCU를 처음으로 설계하는 분들 중 MCU의 핀 하나를 입력으로 설정하여 입력을 받는게 받아들이는 값이 지멋대로 튀어 원치않는 값을 받는 경우를 경험하신 분들이 계실거라 생각합니다. 분명 VCC에 걸리면 HIGH 상태가 되고 GND에 연결하면 LOW 상태가 확실히 걸리는데 유독 아무런 값도 걸지 않은 상태에서는 값이 자기 맘대로 튀어 당황하신 분들도 계실거라 생각합니다.


 이와 같은 현상을 플로팅(Floating)이라 하며, 해당 핀의 상태가 HIGH도 아니고 LOW도 아닌 값을 가지고 있는 상황이 되는 것입니다. 즉, 확실한 값을 가지고 있지 않기 때문에 이 상태에서 입력값을 받으면 MCU는 계속해서 이상한 값을 가지게 되는 것입니다.


 이러한 상태를 해결하는 방법으로 풀업(pull-up)과 풀다운(pull-down) 방식이 있습니다.

 pull-up방식은 해당 입력핀의 연결라인 중간에 저항을 연결하고 해당 저항이 HIGH상태(주로 VCC)에 연결되어 있는 상황을 말합니다. 이렇게 회로를 설계하면 해당 입력핀의 값은 HIGH를 유지하다가 전압이 0으로 내려가면 LOW상태가 되며 값이 플로팅 상태 때보다 매우 안정적인 값을 얻으실 수 있습니다. pull-up 방식은 주로 I2C 통신에서 많이 사용되는 회로 입니다.



 위 그림은 I2C회로의 간략한 회로입니다. I2C회로는 각 기기들과 2개의 선으로 연결되어 있는데 해당 2개의 선인 SDA와 SCL은 다른 기기들과 그냥 연결하게 되면 Open Drain 상태가 되여 마스터의 입력이 HIGH가 되어도 Slave는 LOW값을 받아들이는 상태만 지속됩니다. 이러한 두 선에 pull-up 회로를 연결하게 되면 보통때에 HIGH 상태를 유지하던 회로가 MASTER에 의해 LOW 상태가 되면 똑같이 LOW 상태를 보이며 회로가 원하는 디래 동작을 할 수 있게 됩니다.


 pull-down 방식은 위해서 설명한 pull-up 방식과는 반대로 저항의 끝에 GND를 연결하여 LOW 상태를 유지하게 해줍니다. 이 상태에서 HIGH 값이 들어오게 되면 입력핀에서도 HIGH 값을 받을 수 있게 되는 것입니다. 




 위 그림은 pull-down 방식이 적용된 MCU의 상황입니다. 저항과 GND를 연결한 상태로 값이 들어오고 있지 않는 상황에서는 LOW 상태를 유지하다가 VCC나 다른 장치로부터 값이 들어오게 되면 MCU가 HIGH 상태를 인식할 수 있게 되는 것이지요.


 위와 같은 회로를 설계에 참고하신다면 입력값의 Floating 상태를 적절하게 방지하실 수 있을 것으로 보입니다.



좀 더 자세한 내용을 알고 싶으신 분들께 관련 내용이 잘 정리되어 있는 블로그를 알려드리겠습니다.

http://minyoub.tistory.com/5

300x250

[Tiva] TM4C 시리즈에서 외부인터럽트 구현

임베디드/TI 2014. 7. 26. 22:09

 MCU를 활용하는 사람이면 거의 대다수가 맨 처음 프로그램을 구동할 때GPIO(General Purpose Input Output)를 구현하여 동작을 확인하는 경험을 해보셨을 것이라 생각합니다. TI에서 제공하는 Tiva C 시리즈인 TM4C MCU 시리즈 또한 이를 잘 구현해 놓았지요.


 ATmega시리즈로 순식간에 인터럽트를 설정하시던 분들도 Tiva 시리즈를 다룰 때 다소 해메시는 분들도 계실것이라 생각합니다. 하지만 그렇다고 처음부터 겁을 먹을 필요는 없습니다. 코드로 표현하는 방식이 다를 뿐 다른 MCU들 처럼 구현할 수 있는 기능은 똑같으니 말이지요.


 이번에는 MCU 프로그램의 필수 요소라 할 수 있는 Interrupt를 구현해보도록 하겠습니다. 인터럽트와 관련이 있는 부분은 직접 주석으로 적어두었으므로 하나씩 읽으면서 익혀두셨으면 합니다.

 

 단, 처음에 Input으로 설정한 핀을 그대로 입력하고자 하는 곳에 꽃게 되면 플로팅 상태가 되기 때문에 입력값이 들쭉날쭉 하는 현상이 벌어집니다. 플로팅 상태의 입력을 안정하게 하는 방법은 다음 포스트를 참고해주시길 바랍니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
#include <stdint.h>
#include <stdbool.h>
#include "inc/hw_gpio.h"
#include "inc/hw_ints.h"
#include "inc/hw_memmap.h"
#include "inc/hw_nvic.h"
#include "inc/hw_types.h"
#include "driverlib/debug.h"
#include "driverlib/fpu.h"
#include "driverlib/gpio.h"
#include "driverlib/interrupt.h"
#include "driverlib/pin_map.h"
#include "driverlib/rom.h"
#include "driverlib/sysctl.h"
#include "driverlib/systick.h"
#include "driverlib/timer.h"
#include "driverlib/uart.h"
#include "utils/uartstdio.h"
 
#ifdef DEBUG
void
__error__(char *pcFilename, uint32_t ui32Line)
{
}
#endif
 
    //자신이 설정하고자 하는 인터럽트 핸들러를 설정한다.
void INT_IntHandler(void) {
    ROM_IntDisable(INT_GPIOA);
    GPIOIntClear(GPIO_PORTA_BASE, GPIO_PIN_4 | GPIO_PIN_6);
 
    UARTprintf("Hello, Interrput!\n");
    ROM_IntEnable(INT_GPIOA);
}
 
 
void ConfigureUART(void) {
    //
    // Enable the GPIO Peripheral used by the UART.
    //
    ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
 
    //
    // Enable UART0
    //
    ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0);
 
    //
    // Configure GPIO Pins for UART mode.
    //
    ROM_GPIOPinConfigure(GPIO_PA0_U0RX);
    ROM_GPIOPinConfigure(GPIO_PA1_U0TX);
    ROM_GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1);
 
    //
    // Use the internal 16MHz oscillator as the UART clock source.
    //
    UARTClockSourceSet(UART0_BASE, UART_CLOCK_PIOSC);
 
    //
    // Initialize the UART for console I/O.
    //
    UARTStdioConfig(0, 115200, 16000000);
}
 
int main(void) {
 
    //
    // Enable lazy stacking for interrupt handlers. This allows floating-point
    // instructions to be used within interrupt handlers, but at the expense of
    // extra stack usage.
    //
    ROM_FPULazyStackingEnable();
 
    //
    // Set the clocking to run directly from the crystal.
    //
    ROM_SysCtlClockSet(    SYSCTL_SYSDIV_4 | SYSCTL_USE_PLL | SYSCTL_XTAL_16MHZ | SYSCTL_OSC_MAIN);
 
    //INTERRUPT를 사용할 GPIO핀을 활성화 시킨다.
    ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
 
    // Initialize the UART.
    ConfigureUART();
 
    //인터럽트를 받아들일 핀을 Input으로 설정한다.
    ROM_GPIOPinTypeGPIOInput(GPIO_PORTA_BASE, GPIO_PIN_4 | GPIO_PIN_6);
 
    //인터럽트되는 핀의 입력 형태를 선택한다. LOW에서 HIGH 상태로 넘어갈 때 인터럽트를 발생시키고자 하면
    //GPIO_RISING_EDGE를 선택한다.
    ROM_GPIOIntTypeSet(GPIO_PORTA_BASE, GPIO_PIN_4 | GPIO_PIN_6, GPIO_RISING_EDGE);
 
    //PORTA의 GPIO 인터럽트를 허용한다.
    GPIOIntEnable(GPIO_PORTA_BASE, GPIO_PIN_4 | GPIO_PIN_6);
 
    //PORTA에서 인터럽트가 발생하였을 때 실행할 함수를 설정한다.
    GPIOIntRegister(GPIO_PORTA_BASE, INT_IntHandler);
 
    //인터럽트가 시작되기 전 Clear 시켜준다.(인터럽트 관련 레지스터를 0으로 만든다.)
    GPIOIntClear(GPIO_PORTA_BASE, GPIO_PIN_4 | GPIO_PIN_6);
 
    ROM_IntEnable(INT_GPIOA);
 
    while (1) {
    }
}


4번 핀과 6번 핀에 HIGH_EDGE 입력이 들어오면 mcu에서 인터럽트가 발생하여 설정된 함수를 실행한다.



300x250

[Tiva] TM4C 시리즈에서 타이머 구현

임베디드/TI 2014. 7. 26. 13:53

 MCU를 다룰 때 타이머의 가장 인상적인 점이라면 개발자가 원하는 주기 마다 인터럽트를 발생시켜 구현하고자 하는 동작을 만들 수 있다는 점이지요.

 TM4C에서 타이머의 가장 큰 특징은 1개의 TIMER를 A와 B로 나누어서 사용할 수 있다는 점입니다. 본 예제에서는 각 타이머의 A만을 다루나 A를 B로 바꾸어서 쓰거나 B를 추가 하는 것 만으로도 동작이 되는 것을 보실 수 있습니다.

 2개의 타이머 인터럽트를 사용하여 1초씩 카운트 하는 프로그램을 구성해 보았습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
#include <stdint.h>
#include <stdbool.h>
#include "inc/hw_ints.h"
#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "driverlib/debug.h"
#include "driverlib/fpu.h"
#include "driverlib/gpio.h"
#include "driverlib/interrupt.h"
#include "driverlib/pin_map.h"
#include "driverlib/rom.h"
#include "driverlib/sysctl.h"
#include "driverlib/timer.h"
#include "driverlib/uart.h"
#include "utils/uartstdio.h"
 
uint32_t count=0, count1=0;
 
#ifdef DEBUG
void
__error__(char *pcFilename, uint32_t ui32Line)
{
}
#endif
 
    //TIMER0을 설정하는 인터럽트 핸들러
void Timer0IntHandler(void) {
 
    //
    // Clear the timer interrupt.
    //
    ROM_TimerIntClear(TIMER0_BASE, TIMER_TIMA_TIMEOUT);
 
    count++;
    if(count>=100)
        count=0;
 
    ROM_IntMasterDisable();
    UARTprintf("\r%2d : %2d",count1, count);
    ROM_IntMasterEnable();
}
 
    //TIMER1을 설정하는 인터럽트 핸들러
void Timer1IntHandler(void) {
 
    //
    // Clear the timer interrupt.
    //
    ROM_TimerIntClear(TIMER1_BASE, TIMER_TIMA_TIMEOUT);
 
    count1++;
    if(count1>=60)
        count1=0;
 
    ROM_IntMasterDisable();
    UARTprintf("\r%2d : %2d",count1, count);
    ROM_IntMasterEnable();
}
 
    //UART 출력을 설정한다.
void ConfigureUART(void) {
    //
    // Enable the GPIO Peripheral used by the UART.
    //
    ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
 
    //
    // Enable UART0
    //
    ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0);
 
    //
    // Configure GPIO Pins for UART mode.
    //
    ROM_GPIOPinConfigure(GPIO_PA0_U0RX);
    ROM_GPIOPinConfigure(GPIO_PA1_U0TX);
    ROM_GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1);
 
    //
    // Use the internal 16MHz oscillator as the UART clock source.
    //
    UARTClockSourceSet(UART0_BASE, UART_CLOCK_PIOSC);
 
    //
    // Initialize the UART for console I/O.
    //
    UARTStdioConfig(0, 115200, 16000000);
}
 
int main(void) {
    //
    // Enable lazy stacking for interrupt handlers.  This allows floating-point
    // instructions to be used within interrupt handlers, but at the expense of
    // extra stack usage.
    //
    ROM_FPULazyStackingEnable();
 
    //
    // Set the clocking to run directly from the crystal.
    //
    ROM_SysCtlClockSet(SYSCTL_SYSDIV_1 | SYSCTL_USE_OSC | SYSCTL_OSC_MAIN |
    SYSCTL_XTAL_16MHZ);
 
    //
    // Initialize the UART and write status.
    //
    ConfigureUART();
 
    //
    // TIMER0과 TIMER1이 동작할 수 있도록 설정해준다.
    //
    ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER0);
    ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER1);
 
    //
    // MCU가 인터럽트를 사용할 수 있도록 설정해준다.
    //
    ROM_IntMasterEnable();
 
    //
    // 타이머의 동작 방식을 설정해준다. 매 주기마다 동작할 수 있도록 TIMER_CFG_PERIODIC을 설정한다.
    //
    ROM_TimerConfigure(TIMER0_BASE, TIMER_CFG_PERIODIC);
    ROM_TimerConfigure(TIMER1_BASE, TIMER_CFG_PERIODIC);
 
    //
    // TIMERA의 주기를 설정한다. ROM_SysCtlClockGet()의 값은 MCU의 주파수를 뜻하며 1초당 동작수를 말한다.
    //
    ROM_TimerLoadSet(TIMER0_BASE, TIMER_A, ROM_SysCtlClockGet() / 100);
    ROM_TimerLoadSet(TIMER1_BASE, TIMER_A, ROM_SysCtlClockGet() / 1);
 
    //
    // 각 타이머의 인터럽트를 사용할 수 있도록 설정한다.
    //
    ROM_IntEnable(INT_TIMER0A);
    ROM_IntEnable(INT_TIMER1A);
 
    //
    // 설정한 타이머의 인터럽트가 동작할 수 있도록 허용한다.
    //
    ROM_TimerIntEnable(TIMER0_BASE, TIMER_TIMA_TIMEOUT);
    ROM_TimerIntEnable(TIMER1_BASE, TIMER_TIMA_TIMEOUT);
 
    //
    // 타이머를 동작시킨다.
    //
    ROM_TimerEnable(TIMER0_BASE, TIMER_A);
    ROM_TimerEnable(TIMER1_BASE, TIMER_A);
 
    //
    // Loop forever while the timers run.
    //
    while (1) {
    }
}
 




300x250

mcu를 활용한 진동모터 회로 설계

임베디드/MCU 2014. 7. 25. 23:52


 mcu의 출력을 직접 진동모터에 연결해보니 진동모터에 걸리는 전압이 급격히 낮아지면서 진동모터가 전혀 동작을 하지 않는 것을 깨닫고 방법을 생각하던 중 문득 트랜지스터를 사용하는 방법을 깨닫게 되었습니다.

 전자회로에 대한 기본 베이스가 약하신 분들의 경우 직접 설계를 하는 것이 약간은 어려울 것이라 생각합니다. 대략 아래와 같이 설계해본 결과 진동모터가 수월하게 작동하는 것을 확인할 수 있었습니다.





 대략 회로를 설명드리자면 MCU에서 OUTPUT으로 설정한 핀을 트랜지스터의 Base에 연결하고 진동모터를 Collector에 연결한 후 Emitter는 GND로 연결한 상황입니다.

 Output 단자의 출력이 0일 경우 Collector에는 전류가 흐르지 않습니다.

 Output 단자의 출력이 1일 경우 Collector에는 전류가 흐르게 되어 진동모터가 동작을 하게 됩니다.

 약간은 단순한 회로이지만 다른 MCU의 전압으로는 동작이 곤란한 회로에 활용할 수 있을 것입니다.

300x250

I2C(TWI) 통신

임베디드/MCU 2014. 7. 24. 16:12

 오랜만에 MCU를 다루게 되면서 처음으로 I2C 통신을 사용하는 부품을 쓰는 일이 생겨 무려 3일동안 I2C에 대해 연구를 해보았습니다. 맨 처음엔 TivaWare에 들어있던 I2C 예제를 복붙해서 그냥 빌드시켜 프로그램을 실행해 보았는데 프로그램 구동 자체가 되지 않는 것을 확인하고는 상당히 시간을 많이 들여 공부해야 되겠다는 생각이 들더군요.

 직접 오실로스코프를 사용하여 화면에 나오는 값들을 일일해 측정하며 I2C 통신의 동작원리를 이해하였고 소스코드도 일일히 하나씩 써 가며 파형이 어떻게 달라지는지를 확인한 결과 드디어 센서가 정상적으로 동작함을 확인할 수 있었습니다.

 이후에 I2C를 공부하게 될 사람들에게 조금이나마 도움을 드리고자 I2C 통신에 처음으로 입문하시는 분들께 큰 힘이 되기를 바랍니다.


 I2C는 Inter Integrated Cricuit의 줄임말로 TWI(Two Wire Interface)라고도 불립니다. I2C 통신의 가장 큰 장점은 바로 단 2가닥의 선으로 여러 대의 기기와 연결하여 통신이 가능하다는 점입니다.



 위 그림에서 보았을 때 I2C 통신은 2종류의 주체로 나눌 수 있습니다. 통신의 중심이 되는 Master와 통신을 하고자 하는 주변 기기를 Slave로 설정할 수 있습니다. 일반적으로 mcu 1대와 여러대의 I2C 통신을 지원하는 기기와 연결할 경우 Master 1대와 Slave 여러대로 통신이 가능합니다. 물론 Master는 2대 이상도 가능하다.


 I2C에서 사용되는 두 선은 SDA와 SCL로 구성되어 있습니다. 통신이 개시되었을 때 SDA는 데이터를 주고 받는 역할을 하고 SCL은 동기화를 위한 CLOCK 역할을 합니다. 여기서 Master와 Slave 각각에 SDA와 SCL을 바로 연결해주기만 하면 되는 것이죠. 그러나 이러한 회로만으로는 오픈 드레인(회로에 + 전압이 걸리지 않는 상황) 상태가 되기 때문에 SDA와 SCL 회로에 풀업 저항(Pull-up resistor)을 달아 전압을 공급해 줘야 합니다. 풀업 저항에 대해 자세히 알고 싶으신 분은 아래 블로그를 참조해 주시길 바랍니다.


풀업(pull-up) 풀다운(pull-down) 저항 1

http://air802.tistory.com/2



 I2C 통신이 이루어지지 않고 있는 상황일 때에는 SDA와 SCL은 High 상태를 유지합니다. Master가 I2C 통신을 개시하게 될 때 SDA가 Low 상태로 내려가게 됩니다. 이 때 SCL은 I2C 통신이 시작되었음을 인지하고 클럭 역할을 하기 시작합니다.

 I2C 통신이 완료되었을 때 Master는 I2C 통신을 종료하게 됩니다. SCL이 HIGH 상태로 돌아왔을 때 SDA가 Low에서 High로 변하게 되면 I2C 통신이 완료됩니다.






 I2C Slave는 각각 자신의 고유 주소를 가지고 있습니다. 주소는 총 7비트로 구성되어 있으며 Master에서 맨 처음 통신하기를 원하는 Slave의 주소를 SDA를 통해 전달하면 해당 주소의 Slave는 Master에게 주소를 수신하였다는 ACK를 Low 상태로 끌어내려 마스터에게 발신합니다. 이후 Master는 Slave에게 데이터를 전송할 수 있게 됩니다. 이 때 데이터는 한 번에 8비트씩 여러번 전송이 가능합니다.




 위에서 Slave address가 모두 전송된 뒤 R/S 부분을 보실 수 있습니다. 이는 해당 Slave의 레지스터를 읽거나 쓸건지의 여부를 물어보는 레지스터로 R의 경우 SDA가 High 상태로 Slave에게 Data를 전달받을 수 있으며 S의 경우 SDA가 Low 상태로 Slave에게 Data를 전송할 수 있습니다.

 


참고자료 : http://mintnlatte.tistory.com/201

300x250

[Tiva] Tera Term으로 런치패드와 UART 통신하기

임베디드/TI 2014. 7. 23. 21:35

 마이크로프로세서를 활용해 보신 분들이라면 UART 통신에 대해 상당한 지식을 가지고 있으실 것이라 생각합니다. 특히 ATmega128에서도 UART를 지원하기 때문에 UART 통신에 큰 어려움은 없을 것이라 생각합니다.

 이번 포스트는 TeraTerm 프로그램을 사용하여 TIVA 런치패드와 UART 통신을 하는 방법에 대해 설명드리겠습니다.


우선 TeraTerm을 컴퓨터에 설치합니다.

http://ttssh2.sourceforge.jp/


윗 부분에서 Download 메뉴를 선택합니다.


다운로드 페이지로 넘어오게 되는데 여기서 최신 버전(화면에서는 teraterm-4.83.exe)을 다운로드 받습니다.


다운로드가 완료되면 설치 프로그램을 실행합니다.



I accept the agreement 를 선택하신 후 Next 버튼을 누릅니다.



프로그램을 설치하기 원하시는 경로를 선택합니다.



Standard installation을 선택하신 후 Next 버튼을 누릅니다.



언어를 선택하는 메뉴입니다.

자신이 원하는 언어를 선택하신 후 Next 버튼을 누릅니다.





Install 버튼을 눌러 프로그램을 설치합니다.



TeraTerm 프로그램을 새로 열자마자 다음과 같은 화면이 나타납니다.



시리얼(E)를 선택하신 후 런치패드와 연결된 포트를 선택합니다.

포트명은 'Stellaris Virtual Serial Port'입니다.(COM 번호는 컴퓨터의 상황에 따라 다릅니다.)

만약 ICDI를 설치하지 않으셨거나 오류가 발생할 경우 포트가 보이지 않습니다.

ICDI를 설치하여야만 다음 단계로 진행이 가능합니다.


설치 방법은 다음 포스팅을 참조해주세요.

http://elecs.tistory.com/6




일단 여기까지 진행하셨다면 런치패드와 TeraTerm과의 연결은 성공한 것입니다.

현재 TeraTerm의 전송속도는 9600으로 런치패드에서 설정한 전송속도와 맟지 않을 경우 글자가 깨져서 출력됩니다.

서로 속도를 맟주기 위해 TeraTerm의 설정을 변경하도록 합니다.

설정 → 시리얼포트를 선택합니다.



시리얼포트의 전송속도를 설정합니다.

TivaWare에 있는 예제인 hello 프로젝트의 경우 속도는 115200입니다.




코드 내부에서 UARTStdioConfig() 함수에서 전송속도를 확인하실 수 있습니다.

전송속도는 두번째 인자인 115200입니다.


코드의 메인에 다음과 같은 함수를 입력합니다.

UARTprintf("Hello, world!");

위 함수는 C언어의 printf() 함수와 기능이 거의 동일합니다.


TeraTerm 화면이 다음과 같으면 통신은 성공한 것입니다.



차후 계속해서 한 가지의 런치패드만으로 UART 통신을 하시는 분들이라면 설정을 통해 TeraTerm을 실행하자마자 설정했던 사항 그대로 프로그램을 바로 실행할 수 있습니다.


설정 → 저장하기를 선택합니다.



TERATERM.ini 파일에 덮어쓰기를 하시면 다음에 실행하실 때 현재 설정된 사항으로 프로그램을 바로 실행하실 수 있습니다.



300x250

[Tiva] Tiva C 런치패드에 프로그램 올리기

임베디드/TI 2014. 7. 21. 12:22

※이 과정을 진행하기 위해서는 다음과 같은 과정이 진행되어야 합니다.

1. CCS(Code Composer Studio) 가 설치되어야 합니다. (6.00 버전으로 진행)

2. Tiva C 런치패드를 디버그 모드로 한 후 USB로 연결 되어있어야 합니다.

3. 프로젝트르 불러들일 파일이 필요합니다.(여기서는 TivaWare를 불러오는 것으로 하겠습니다.)

4. ICDI 드라이버가 설치되어 있어야 합니다.


설치한 Code Composer Studio를 실행합니다.


실행한 후 메뉴에서 Project → Import CCS Projects... 를 선택합니다.



다음과 같은 메뉴가 등장하게 됩니다.

차후 자신이 만든 프로그램들이 실행될 수 있게 해주는 driverlib를 Project Explorer에 올려보도록 하겠습니다.

Browse... 를 클릭합니다.



자신이 TivaWare를 설치하였던 폴더를 연 후 driverlib 폴더를 클릭 후 확인 버튼을 누릅니다.



다음 화면과 같이 driverlib 프로젝트가 표시되면 아랫쪽에 Finish 버튼을 클릭합니다.



Project Explorer에 driverlib가 추가되어 있는 것을 확인하실 수 있습니다.

이번에는 우리들이 동작시키기를 원하는 프로젝트를 불러와 보도록 하겠습니다.



driverlib 폴더를 불러왔었을 때 처럼의 과정을 반복합니다.

이번에는 TivaWare 폴더 하위에 있는 examples → boards 폴더를 열어보면

보시는 바와 같이 Tiva 시리즈의 각 보드들의 예제들을 확인하실 수 있습니다.

해당 메뉴에서 자신의 런치패드에 해당하는 폴더를 엽니다.

(여기서는 TM4C123G 런치패드를 기준으로 하겠습니다.)



자신이 실행하기를 원하는 프로젝트의 폴더를 다음과 같이 선택하신 후 확인 버튼을 클릭합니다.



다음과 같이 자신이 실행하고자 하는 프로젝트가 확인 되면 Finish 버튼을 클릭합니다.



불러들인 프로젝트에 마우스 오른쪽 버튼을 클릭한 후 Build Project를 실행합니다.



클릭하게 되면 CCS가 해당 프로젝트를 Build 하는 과정을 확인하실 수 있습니다.



Build가 완료되면 Debug 버튼을 눌러 런치패드에 프로그램을 구동해봅니다.



CCS가 디버그 모드에 진입함과 동시에 런치패드에 프로그램을 설치하게 됩니다.



디버그 준비가 완료되면 메뉴에서 화살표 버튼을 클릭하면 곧바로 프로그램이 동작함을 확인하실 수 있습니다.



300x250