Interrupt Driven STM32

PA11 as a Interrupt Source

Modify the code as following snippet, we will set PA11 as interrupt invoke.

1
2
3
4
5
GPIO_InitStruct.Pin = GPIO_PIN_11;
GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_LOW;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

Handle the Interrupt

We must modify the code in interrupt handler.

1
2
3
4
5
6
7
8
void EXTI15_10_IRQHandler(void){
if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_11)!=0){
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_11);
}
if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_12)!=0){
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_12);
}
}

We need to recognize the interrupt source in the handler.

Callback

Hence, we could separate the GPIO_Pin in the callback function.

1
2
3
4
5
6
7
8
9
10
11
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin){
switch (GPIO_Pin){
case GPIO_PIN_11:
printf("Pressed\r\n");
mode=!mode;
break;
case GPIO_PIN_12:
counter++;
break;
}
}

Enter the Sleep Mode

First, we must diable system tick interrupt. And then, the program must sleep again after the interrupt is handled.

1
2
3
4
5
6
7
8
HAL_SuspendTick();
HAL_PWR_EnterSLEEPMode(PWR_MAINREGULATOR_ON, PWR_SLEEPENTRY_WFI);
HAL_PWR_EnableSleepOnExit();
while (1)
{
printf("CPU running!\r\n");
HAL_Delay(100);
}

Result


As you can see, the CPU running! in a dead loop only execute once. And other function run well.

Getting Started with STM32 in Windows

Connect the Circuit

In the very first of this experiment, we have to connect the circuit. There is three parts waited to be connect. First, connect the ST-LINK. Second, conect the CP2012. And finally, connect the button to pins on STM32.

In order to get through the ST-LINK, two steps must be done. The very first step is connect the pins with Dupont Lines. Here is the corresponding pins.

ST-LINK STM32
SWCLK DCLK
SWDIO DIO
GND GND
3.3V 3.3V

Next, the driver must be installed.

Connect CP2012

Similarly, I will give the corresponding pins talbe.

CP2012 STM32
3.3v 3.3v
GND GND
TXD A10
RXD A9

And, of course, make sure driver running correctly.

Connect Button

There are two four ports in one button. In order to input separtely, only two ports could be used. One is connected to ‘GND’ and one is connected to ‘PA11’ or ‘PA12’.

Here is the circut diagram.

Configuration

In my opinion, there is some configuration need to be mentioned.

Comment Removal

The some comment mark in stm32f1xx_hal_conf.h must be remove, so that the compiler would link them into executable.

Especially, following two #define must be released. Because we must use UART, TIM and GPIO.

1
2
3
#define HAL_GPIO_MODULE_ENABLED
#define HAL_TIM_MODULE_ENABLED
#define HAL_UART_MODULE_ENABLED

Programming Algorithm

The Programming Algorithm must be added, otherwise, we couldn’t program. You could find this dialog in given documentation.

Initialize UART

One handler must be defined, so that we could initialize with it.

1
UART_HandleTypeDef UartHandler;

This variable could be global or local. Next, set parameters and initialize.

1
2
3
4
5
6
7
8
UartHandler.Instance        = USART1;
UartHandler.Init.BaudRate = 9600;
UartHandler.Init.WordLength = UART_WORDLENGTH_8B;
UartHandler.Init.StopBits = UART_STOPBITS_1;
UartHandler.Init.Parity = UART_PARITY_NONE;
UartHandler.Init.HwFlowCtl = UART_HWCONTROL_NONE;
UartHandler.Init.Mode = UART_MODE_TX_RX;
HAL_UART_Init(&UartHandler);

Rewrite Output

Our intent is use printf function write the data to the serial port. So, two function need to be rewritten, which are int __io_putchar(uint8_t ch) and int fputc(int ch, FILE *f) respectively.

1
2
3
4
5
6
7
8
9
10
int __io_putchar(uint8_t ch){
HAL_UART_Transmit(&UartHandler, &ch, 1, 100);
return 1;
}

int fputc(int ch, FILE *f){
uint8_t chr =ch;
HAL_UART_Transmit(&UartHandler, &chr, 1, 100);
return 1;
}

Now the output would be directed to the serial port.

GPIO Initilization

Two pins must be initilized, PA11 and PA12.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
GPIO_InitTypeDef GPIO_InitStruct;

__GPIOA_CLK_ENABLE();

GPIO_InitStruct.Pin = GPIO_PIN_11;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_LOW;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

GPIO_InitStruct.Pin = GPIO_PIN_12;
GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_LOW;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

HAL_NVIC_SetPriority(EXTI15_10_IRQn,0,0);
HAL_NVIC_EnableIRQ(EXTI15_10_IRQn);

The function HAL_GPIO_Init(GPIOA, &GPIO_InitStruct) would call void HAL_UART_MspInit(UART_HandleTypeDef *huart) in stm32f1xx_hal_msp.c. Thus we must fill the code.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
void HAL_UART_MspInit(UART_HandleTypeDef *huart)
{

__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_USART1_CLK_ENABLE();

GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.Pin = GPIO_PIN_9;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
GPIO_InitStruct.Pin = GPIO_PIN_10;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}

void HAL_UART_MspDeInit(UART_HandleTypeDef *huart)
{

__HAL_RCC_USART1_FORCE_RESET();
__HAL_RCC_USART1_RELEASE_RESET();
HAL_GPIO_DeInit(GPIOA, GPIO_PIN_9);
HAL_GPIO_DeInit(GPIOA, GPIO_PIN_10);
}

If __GPIOA_CLK_ENABLE() is not called, the input of PA11 would be strange, like a clock. Thus you shouldn’t forget it. And HAL_NVIC_SetPriority(EXTI15_10_IRQn,0,0) and HAL_NVIC_EnableIRQ(EXTI15_10_IRQn) would set the interrupt for PA12. Now, we need a callback function to handle the push.
Add a function in stm32f1xx_it.c to handle the interrupt.

1
2
3
void EXTI15_10_IRQHandler(void){
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_12);
}

This function would call void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin), so it’s necessary to implement it in main.c.

1
2
3
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin){
counter++;
}

According to the requirement, we need to increase counter. So far, we’ve handle the input of PA12. Next, we would handle the PA11 in main loop. Add following code snipet in int main(void)

1
2
3
4
if ((HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_11))==0) {
printf("Pressed\r\n");
mode=!mode;
}

Change the mode, of course, and remember that, this condition statement must be enclosed by a loop.

Timer Initialization

Follwing code snippet is to set the serial port parameters. However, I don’t the specific meaning of this statements.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
TIM_ClockConfigTypeDef sClockSourceConfig;
TIM_MasterConfigTypeDef sMasterConfig;

TIM_Handler.Instance = TIM3;
TIM_Handler.Init.Prescaler = 48000;
TIM_Handler.Init.CounterMode = TIM_COUNTERMODE_UP;
TIM_Handler.Init.Period = 199;
TIM_Handler.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
HAL_TIM_Base_Init(&TIM_Handler);

sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
HAL_TIM_ConfigClockSource(&TIM_Handler, &sClockSourceConfig);

sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
HAL_TIMEx_MasterConfigSynchronization(&TIM_Handler, &sMasterConfig);

Then call this function

1
HAL_TIM_Base_Start_IT(&TIM_Handler);

And this function cooperate with other two function that we must implement in stm32f1xx_hal_msp.c.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* htim_base)
{

if(htim_base->Instance==TIM3)
{
__TIM3_CLK_ENABLE();
HAL_NVIC_SetPriority(TIM3_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(TIM3_IRQn);
}
}

void HAL_TIM_Base_MspDeInit(TIM_HandleTypeDef* htim_base)
{


if(htim_base->Instance==TIM3)
{
__TIM3_CLK_DISABLE();
HAL_NVIC_DisableIRQ(TIM3_IRQn);
}
}

Similarly, we need to append a handler in stm32f1xx_it.c.

1
2
3
4
void TIM3_IRQHandler(void)
{

HAL_TIM_IRQHandler(&TIM_Handler);
}

And the function HAL_TIM_IRQHandler(&TIM_Handler) would call a callback function whose name is void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim). Just like the condition above, the implementation is necessary.

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim){
    if(htim->Instance == TIM3){        
        timer_flag = 1;
        timer_counter++;
    }
}

Result

Finally, we could check the results.

Print Hello as request.

Press PA11 to change the mode and press PA12 to increment distance. The timer counter is always accumalted. For now, I’ve finished the required part.

Stuff in ARM Instruction

This article would study ARM instruction set and how special instruction works and how to implement the function call.

Thumb VS ARM

In this section, I will compare ARM instructions and Thumb instructions. First of all, I will present the code analysed.

1
2
3
4
5
6
7
#include<stdio.h>

int main(void){
int i;
for (i=0; i < 10; i++);
return 0;
}

And I utilized the cross-compile tools in Ubuntu to compile the code.

1
2
arm-linux-gnueabi-gcc test.c -o test.a
arm-linux-gnueabi-gcc test.c -mthumb -o test.t

Secondly, use the objdump tool in cross-compile kit to inspect the assemble code.

1
2
arm-linux-gnueabi-objdump -d test.a
arm-linux-gnueabi-objdump -d test.t

ARM code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
0000840c <main>:
840c: e52db004 push {fp} ; (str fp, [sp, #-4]!)
8410: e28db000 add fp, sp, #0
8414: e24dd00c sub sp, sp, #12
8418: e3a03000 mov r3, #0
841c: e50b3008 str r3, [fp, #-8]
8420: ea000002 b 8430 <main+0x24>
8424: e51b3008 ldr r3, [fp, #-8]
8428: e2833001 add r3, r3, #1
842c: e50b3008 str r3, [fp, #-8]
8430: e51b3008 ldr r3, [fp, #-8]
8434: e3530009 cmp r3, #9
8438: dafffff9 ble 8424 <main+0x18>
843c: e3a03000 mov r3, #0
8440: e1a00003 mov r0, r3
8444: e28bd000 add sp, fp, #0
8448: e8bd0800 ldmfd sp!, {fp}
844c: e12fff1e bx lr

As you can see, all instruction compose of 32 bits.

Thumb code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
0000840c <main>:
840c: b580 push {r7, lr}
840e: b082 sub sp, #8
8410: af00 add r7, sp, #0
8412: 2300 movs r3, #0
8414: 607b str r3, [r7, #4]
8416: e002 b.n 841e <main+0x12>
8418: 687b ldr r3, [r7, #4]
841a: 3301 adds r3, #1
841c: 607b str r3, [r7, #4]
841e: 687b ldr r3, [r7, #4]
8420: 2b09 cmp r3, #9
8422: ddf9 ble.n 8418 <main+0xc>
8424: 2300 movs r3, #0
8426: 1c18 adds r0, r3, #0
8428: 46bd mov sp, r7
842a: b002 add sp, #8
842c: bd80 pop {r7, pc}
842e: 46c0 nop ; (mov r8, r8)

The instruction consist of 16 bits as our wish. Compare with ARM instructions, this code is only half length. But the number of instructions is similar. That means similar execution time but much shorter program length.

1
2
-rwxrwxr-x 1 sea sea 8346 Mar 31 07:08 test.a
-rwxrwxr-x 1 sea sea 8349 Mar 31 07:08 test.t

However, the Thumb code executable is bit longer. Of course, the main part of a executable is other code which is prepared for operating system, that is ARM instructions.

Condition Instruction

In this section I will present how to construct the condition execution instructions. Because the compiler would generate normal instruction as a default approach, the optimization option must be galvanized. Of course, the target code must be demonstrated at first.

1
2
3
4
5
6
7
8
9
10
11
#include<stdio.h>

int main(void){
int a, b;
scanf("%d %d", &a, &b);
if (a>b)
a++;
else
b++;
printf("%d %d", a, b);
}

And the compile script.

1
arm-linux-gnueabi-gcc test.c -o test.a -O

Now we could see the condition instructions.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
0000849c <main>:
849c: e52de004 push {lr} ; (str lr, [sp, #-4]!)
84a0: e24dd00c sub sp, sp, #12
84a4: e59f0040 ldr r0, [pc, #64] ; 84ec <main+0x50>
84a8: e1a0100d mov r1, sp
84ac: e28d2004 add r2, sp, #4
84b0: ebffffa6 bl 8350 <_init+0x44>
84b4: e59d2000 ldr r2, [sp]
84b8: e59d3004 ldr r3, [sp, #4]
84bc: e1520003 cmp r2, r3
84c0: c2822001 addgt r2, r2, #1
84c4: c58d2000 strgt r2, [sp]
84c8: d2833001 addle r3, r3, #1
84cc: d58d3004 strle r3, [sp, #4]
84d0: e3a00001 mov r0, #1
84d4: e59f1010 ldr r1, [pc, #16] ; 84ec <main+0x50>
84d8: e59d2000 ldr r2, [sp]
84dc: e59d3004 ldr r3, [sp, #4]
84e0: ebffff97 bl 8344 <_init+0x38>
84e4: e28dd00c add sp, sp, #12
84e8: e8bd8000 ldmfd sp!, {pc}
84ec: 00008564 .word 0x00008564

Register Shift

Let’s construct scenario that would generate register shift instruction. Target code is here.

1
2
3
4
5
6
7
int main(void){
int a, b;
scanf("%d %d", &a, &b);
a = a + b << 4;
a = a + b << 4;
printf("%d %d", a, b);
}

Of course, in order to avoid the compiler generate normal instruction we must use the optimization option. However, the optimization would eliminate every code because of the unuse of variable. Thus, input and output is introduced.

1
arm-linux-gnueabi-gcc test.c -o test.a -O

Dump it, check the machine code.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
0000849c <main>:
849c: e92d4010 push {r4, lr}
84a0: e24dd008 sub sp, sp, #8
84a4: e59f4038 ldr r4, [pc, #56] ; 84e4 <main+0x48>
84a8: e1a00004 mov r0, r4
84ac: e1a0100d mov r1, sp
84b0: e28d2004 add r2, sp, #4
84b4: ebffffa5 bl 8350 <_init+0x44>
84b8: e59d3004 ldr r3, [sp, #4]
84bc: e59d2000 ldr r2, [sp]
84c0: e0832002 add r2, r3, r2
84c4: e0832202 add r2, r3, r2, lsl #4
84c8: e1a02202 lsl r2, r2, #4
84cc: e58d2000 str r2, [sp]
84d0: e3a00001 mov r0, #1
84d4: e1a01004 mov r1, r4
84d8: ebffff99 bl 8344 <_init+0x38>
84dc: e28dd008 add sp, sp, #8
84e0: e8bd8010 pop {r4, pc}
84e4: 0000855c .word 0x0000855c

Load a 32-bits number

Now, I will show how the assigment is implemented.

1
2
3
4
5
6
7
8
#include<stdio.h>

int main(void){
int a, b;
scanf("%d %d", &a, &b);
a=0x12312312;
printf("%d %d", a, b);
}

Variable int a would be assigned by a 32-bits number. Compile it, and check the assemble language.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
00008494 <main>:
8494: e92d4800 push {fp, lr}
8498: e28db004 add fp, sp, #4
849c: e24dd008 sub sp, sp, #8
84a0: e24b200c sub r2, fp, #12
84a4: e24b3008 sub r3, fp, #8
84a8: e59f0034 ldr r0, [pc, #52] ; 84e4 <main+0x50>
84ac: e1a01002 mov r1, r2
84b0: e1a02003 mov r2, r3
84b4: ebffffa3 bl 8348 <_init+0x44>
84b8: e59f3028 ldr r3, [pc, #40] ; 84e8 <main+0x54>
84bc: e50b300c str r3, [fp, #-12]
84c0: e51b200c ldr r2, [fp, #-12]
84c4: e51b3008 ldr r3, [fp, #-8]
84c8: e59f0014 ldr r0, [pc, #20] ; 84e4 <main+0x50>
84cc: e1a01002 mov r1, r2
84d0: e1a02003 mov r2, r3
84d4: ebffff92 bl 8324 <_init+0x20>
84d8: e1a00003 mov r0, r3
84dc: e24bd004 sub sp, fp, #4
84e0: e8bd8800 pop {fp, pc}
84e4: 00008560 .word 0x00008560
84e8: 12312312 .word 0x12312312

As you can see, the constant is stored in bottom of code. And the content in the memory would be load into register directly by using instruction ldr.

Function Call

Function call is a important part in every program. So that, I will study the function call mechanism in this section.
Let’s present the target code as ususal.

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
#include<stdio.h>

int x(int a){
a=0x440;
printf("%d", a);
}

int g(int a, int b){
b=0x220;
b = b+1;
x(b);
b = b+1;
}

int f(int a){
int b=0x130;
b = b+1;
g(b, a);
b = b+1;
}

int main(void){
int a, b;
scanf("%d %d", &a, &b);
a=0x12312312;
f(a);
printf("%d %d", a, b);
}

Then, compile it and inspect the machine code.

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
00008510 <f>:
8510: e92d4800 push {fp, lr}
8514: e28db004 add fp, sp, #4
8518: e24dd010 sub sp, sp, #16
851c: e50b0010 str r0, [fp, #-16]
8520: e3a03e13 mov r3, #304 ; 0x130
8524: e50b3008 str r3, [fp, #-8]
8528: e51b3008 ldr r3, [fp, #-8]
852c: e2833001 add r3, r3, #1
8530: e50b3008 str r3, [fp, #-8]
8534: e51b0008 ldr r0, [fp, #-8]
8538: e51b1010 ldr r1, [fp, #-16]
853c: ebffffe1 bl 84c8 <g>
8540: e51b3008 ldr r3, [fp, #-8]
8544: e2833001 add r3, r3, #1
8548: e50b3008 str r3, [fp, #-8]
854c: e1a00003 mov r0, r3
8550: e24bd004 sub sp, fp, #4
8554: e8bd8800 pop {fp, pc}

00008558 <main>:
8558: e92d4800 push {fp, lr}
855c: e28db004 add fp, sp, #4
8560: e24dd008 sub sp, sp, #8
8564: e24b200c sub r2, fp, #12
8568: e24b3008 sub r3, fp, #8
856c: e59f0040 ldr r0, [pc, #64] ; 85b4 <main+0x5c>
8570: e1a01002 mov r1, r2
8574: e1a02003 mov r2, r3
8578: ebffff72 bl 8348 <_init+0x44>
857c: e59f3034 ldr r3, [pc, #52] ; 85b8 <main+0x60>
8580: e50b300c str r3, [fp, #-12]
8584: e51b300c ldr r3, [fp, #-12]
8588: e1a00003 mov r0, r3
858c: ebffffdf bl 8510 <f>
8590: e51b200c ldr r2, [fp, #-12]
8594: e51b3008 ldr r3, [fp, #-8]
8598: e59f0014 ldr r0, [pc, #20] ; 85b4 <main+0x5c>
859c: e1a01002 mov r1, r2
85a0: e1a02003 mov r2, r3
85a4: ebffff5e bl 8324 <_init+0x20>
85a8: e1a00003 mov r0, r3
85ac: e24bd004 sub sp, fp, #4
85b0: e8bd8800 pop {fp, pc}
85b4: 00008634 .word 0x00008634
85b8: 12312312 .word 0x12312312

00008494 <x>:
8494: e92d4800 push {fp, lr}
8498: e28db004 add fp, sp, #4
849c: e24dd010 sub sp, sp, #16
84a0: e50b0010 str r0, [fp, #-16]
84a4: e3a03d11 mov r3, #1088 ; 0x440
84a8: e50b3008 str r3, [fp, #-8]
84ac: e59f0010 ldr r0, [pc, #16] ; 84c4 <x+0x30>
84b0: e51b1008 ldr r1, [fp, #-8]
84b4: ebffff9a bl 8324 <_init+0x20>
84b8: e1a00003 mov r0, r3
84bc: e24bd004 sub sp, fp, #4
84c0: e8bd8800 pop {fp, pc}
84c4: 00008630 .word 0x00008630

000084c8 <g>:
84c8: e92d4800 push {fp, lr}
84cc: e28db004 add fp, sp, #4
84d0: e24dd010 sub sp, sp, #16
84d4: e50b0010 str r0, [fp, #-16]
84d8: e50b1014 str r1, [fp, #-20]
84dc: e3a03e22 mov r3, #544 ; 0x220
84e0: e50b3008 str r3, [fp, #-8]
84e4: e51b3008 ldr r3, [fp, #-8]
84e8: e2833001 add r3, r3, #1
84ec: e50b3008 str r3, [fp, #-8]
84f0: e51b0008 ldr r0, [fp, #-8]
84f4: ebffffe6 bl 8494 <x>
84f8: e51b3008 ldr r3, [fp, #-8]
84fc: e2833001 add r3, r3, #1
8500: e50b3008 str r3, [fp, #-8]
8504: e1a00003 mov r0, r3
8508: e24bd004 sub sp, fp, #4
850c: e8bd8800 pop {fp, pc}

Return Address

The return address would be stored in register lr when the instruction bl is executed. And whenever the call is invoked, the return address would be pushed into stack.

Parameter Passing

The parameter is passed through register R0 and R1.

Local Variable

The variable would be allocated when the function call is made. First of all, the local stack space woudl be allocated by frame pointer. After the return address is pushed to the stack, the local variable would stored sequentially.

Reigster Save

R0-R3 is saved by caller but the register above R4 is saved by callee.

BIC

In order to obtin the BIC instruction, we must do some operation that is similiar to the logic of this instruction.

1
2
3
4
5
6
7
8
#include<stdio.h>

int main(void){
int a, b, c, d;
scanf("%d %d %d %d", &a, &b, &c, &d);
a = b & (~c);
printf("%d %d %d %d", a, b, c, d);
}

And, the optimazation option is necessary.

1
arm-linux-gnueabi-gcc test.c -o test.a -O

Then, we could find out the BIC instruction.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
0000849c <main>:
849c: e92d4010 push {r4, lr}
84a0: e24dd018 sub sp, sp, #24
84a4: e59f4048 ldr r4, [pc, #72] ; 84f4 <main+0x58>
84a8: e28d3014 add r3, sp, #20
84ac: e58d3000 str r3, [sp]
84b0: e1a00004 mov r0, r4
84b4: e28d1008 add r1, sp, #8
84b8: e28d200c add r2, sp, #12
84bc: e28d3010 add r3, sp, #16
84c0: ebffffa2 bl 8350 <_init+0x44>
84c4: e59d1010 ldr r1, [sp, #16]
84c8: e59d300c ldr r3, [sp, #12]
84cc: e1c32001 bic r2, r3, r1
84d0: e58d2008 str r2, [sp, #8]
84d4: e58d1000 str r1, [sp]
84d8: e59d1014 ldr r1, [sp, #20]
84dc: e58d1004 str r1, [sp, #4]
84e0: e3a00001 mov r0, #1
84e4: e1a01004 mov r1, r4
84e8: ebffff95 bl 8344 <_init+0x38>
84ec: e28dd018 add sp, sp, #24
84f0: e8bd8010 pop {r4, pc}
84f4: 0000856c .word 0x0000856c

Inline Assembly

In this section, I write a pure ARM assembly function. There is one thing deserved to be mentioned, which is we must store and load the return address, so that the function would be executed properly.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include<stdio.h>

asm(
"test:"
"push {r3, r4, fp, lr}\n"
"add r3, r0, r1\n"
"mov r4, #0\n"
"strb r4, [r3]\n"
"bl puts\n"
"pop {r3, r4, fp, pc}\n"
);

int main(void){
char s[10]="abcdefghij";
test(s, 3);
}

And I invoke the function puts to print the string.

Getting started with RaspberryPi

I have gotten through the serial port connection of RaspberryPi. Besides, our development board is not
brand new, so the refurbishment is necessary.

Refurbishment of Raspbian

In this section, I will introduce how download operating system image to this board. At the very first, you must prepare Win32DiskImager and a OS image like 2016-02-26-raspbian-jessie-lite.img as I used. Now, insert your SD card to the computer and make sure the lock on SD card is opened.

Open Disk Imager and write image to the board.

Get through the Serial Port

In order to avoid your confusion, the I prefer presenting the connection picture instead of circuit. Of course, you must ensure that your serial port driver work out. You could consult Getting Started with WRTNode on Windows 8.1 for detail.

Open putty and input Serial line and Speed like below image, them click Open.

As you can, we connect succecfully. Besides, your default login name is pi and password is raspberry.
By connection using serial port, you could read the Starting Content. Unfortunately, in my windows 8.1 platform, the bug of serial port driver would lead a crash of system. Thus, I prefer another way to connect Raspberry.

Connection by LAN

By using a cable connecting Raspberry Pi with Router, Raspberry Pi could be visted like a client.

Also, the router device manager would show your IP of Raspberry Pi.

It’s time to login with Putty.

Cross Compiling

PC is better place to develop software, which is the motivation of Cross Compiling. However, windows is not a good place for raspberry development. I couldn’t find cros compiling tools for windows, but for linux.
In Ubuntu 14.04, apt-get is utilized to gain the tools.

1
2
3
apt-get install gcc-arm-linux-gnueabi make ncurses-dev
arm-linux-gnueabi-gcc hello.c
scp a.out pi@192.168.1.101:~/hello.out

When you compile the file successfully, you could scp the executable to the raspberrypi. And, execute! Then you could see that.

1
Hello World!

Starting Content

Uncompressing Linux… done, booting the kernel.
[ 0.000000] Booting Linux on physical CPU 0x0 //Linux would execute from address 0x0
[ 0.000000] Initializing cgroup subsys cpuset //initialize subsystem cpuset
[ 0.000000] Initializing cgroup subsys cpu
[ 0.000000] Initializing cgroup subsys cpuacct
[ 0.000000] Linux version 4.1.18+ (dc4@dc4-XPS13-9333) (gcc version 4.9.3 (crosstool-NG crosstool-ng-1.22.0-88-g8460611) ) #846 Thu Feb 25 14:11:56 GMT 2016 //Linux Version
[ 0.000000] CPU: ARMv6-compatible processor [410fb767] revision 7 (ARMv7), cr=00c5387d // CPU information
[ 0.000000] CPU: PIPT / VIPT nonaliasing data cache, VIPT nonaliasing instruction cache
[ 0.000000] Machine model: Raspberry Pi Model B Rev 2 // Booting model of raspberry
[ 0.000000] cma: Reserved 8 MiB at 0x1b400000
[ 0.000000] Memory policy: Data cache writeback // cache strategy
[ 0.000000] Built 1 zonelists in Zone order, mobility grouping on. Total pages: 113680
[ 0.000000] Kernel command line: dma.dmachans=0x7f35 bcm2708_fb.fbwidth=656 bcm2708_fb.fbheight=416 bcm2708.boardrev=0xf bcm2708.serial=0xb633a796 smsc95xx.macaddr=B8:27:EB:33:A7:96 bcm2708_fb.fbswap=1 bcm2708.uart_clock=3000000 vc_mem.mem_base=0x1ec00000 vc_mem.mem_size=0x20000000 dwc_otg.lpm_enable=0 console=ttyAMA0,115200 console=tty1 root=/dev/mmcblk0p2 rootfstype=ext4 elevator=deadline fsck.repair=yes rootwait
[ 0.000000] PID hash table entries: 2048 (order: 1, 8192 bytes)
[ 0.000000] Dentry cache hash table entries: 65536 (order: 6, 262144 bytes)
[ 0.000000] Inode-cache hash table entries: 32768 (order: 5, 131072 bytes)
[ 0.000000] Memory: 436836K/458752K available (5792K kernel code, 488K rwdata, 1788K rodata, 352K init, 720K bss, 13724K reserved, 8192K cma-reserved)
[ 0.000000] Virtual kernel memory layout: // memory layout
[ 0.000000] vector : 0xffff0000 - 0xffff1000 ( 4 kB)
[ 0.000000] fixmap : 0xffc00000 - 0xfff00000 (3072 kB)
[ 0.000000] vmalloc : 0xdc800000 - 0xff000000 ( 552 MB)
[ 0.000000] lowmem : 0xc0000000 - 0xdc000000 ( 448 MB)
[ 0.000000] modules : 0xbf000000 - 0xc0000000 ( 16 MB)
[ 0.000000] .text : 0xc0008000 - 0xc076f1f0 (7581 kB)
[ 0.000000] .init : 0xc0770000 - 0xc07c8000 ( 352 kB)
[ 0.000000] .data : 0xc07c8000 - 0xc0842260 ( 489 kB)
[ 0.000000] .bss : 0xc0842260 - 0xc08f63e0 ( 721 kB)
[ 0.000000] SLUB: HWalign=32, Order=0-3, MinObjects=0, CPUs=1, Nodes=1
[ 0.000000] NR_IRQS:522
[ 0.000000] clocksource stc: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 1911260446275 ns
[ 0.000014] sched_clock: 32 bits at 1000kHz, resolution 1000ns, wraps every 2147483647500ns
[ 0.000055] Switching to timer-based delay loop, resolution 1000ns
[ 0.000339] Console: colour dummy device 80x30
[ 0.001263] console [tty1] enabled
[ 0.001322] Calibrating delay loop (skipped), value calculated using timer frequency.. 2.00 BogoMIPS (lpj=10000)
[ 0.001407] pid_max: default: 32768 minimum: 301
[ 0.001784] Mount-cache hash table entries: 1024 (order: 0, 4096 bytes)
[ 0.001854] Mountpoint-cache hash table entries: 1024 (order: 0, 4096 bytes)
[ 0.002904] Initializing cgroup subsys blkio // initialize other sub systems
[ 0.002997] Initializing cgroup subsys memory
[ 0.003068] Initializing cgroup subsys devices
[ 0.003131] Initializing cgroup subsys freezer
[ 0.003191] Initializing cgroup subsys net_cls
[ 0.003309] CPU: Testing write buffer coherency: ok
[ 0.003428] ftrace: allocating 19747 entries in 58 pages
[ 0.107997] Setting up static identity map for 0x81c0 - 0x81f8
[ 0.110174] devtmpfs: initialized
[ 0.120996] VFP support v0.3: implementor 41 architecture 1 part 20 variant b rev 5
[ 0.121448] clocksource jiffies: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 19112604462750000 ns
[ 0.123452] pinctrl core: initialized pinctrl subsystem
[ 0.124353] NET: Registered protocol family 16
[ 0.129822] DMA: preallocated 4096 KiB pool for atomic coherent allocations //DMA information
[ 0.131309] bcm2708.uart_clock = 3000000
[ 0.136188] hw-breakpoint: found 6 breakpoint and 1 watchpoint registers.
[ 0.136264] hw-breakpoint: maximum watchpoint size is 4 bytes.
[ 0.136469] Serial: AMBA PL011 UART driver
[ 0.136768] 20201000.uart: ttyAMA0 at MMIO 0x20201000 (irq = 83, base_baud = 0) is a PL011 rev2
[ 0.504783] console [ttyAMA0] enabled
[ 0.509180] bcm2835-mbox 2000b880.mailbox: mailbox enabled
[ 0.555152] bcm2708-dmaengine 20007000.dma: DMA legacy API manager at f2007000, dmachans=0xf35
[ 0.563881] bcm2708-dmaengine 20007000.dma: Initialized 7 DMA channels (+ 1 legacy)
[ 0.572447] bcm2708-dmaengine 20007000.dma: Load BCM2835 DMA engine driver
[ 0.579375] bcm2708-dmaengine 20007000.dma: dma_debug:0
[ 0.585524] SCSI subsystem initialized
[ 0.589687] usbcore: registered new interface driver usbfs
[ 0.595405] usbcore: registered new interface driver hub
[ 0.600937] usbcore: registered new device driver usb
[ 0.606962] raspberrypi-firmware soc:firmware: Attached to firmware from 2016-02-25 14:25
[ 0.642645] Switched to clocksource stc
[ 0.695761] FS-Cache: Loaded
[ 0.699061] CacheFiles: Loaded
[ 0.717829] NET: Registered protocol family 2
[ 0.723757] TCP established hash table entries: 4096 (order: 2, 16384 bytes)//initialize TCP
[ 0.730947] TCP bind hash table entries: 4096 (order: 2, 16384 bytes)
[ 0.737578] TCP: Hash tables configured (established 4096 bind 4096)
[ 0.744216] UDP hash table entries: 256 (order: 0, 4096 bytes)
[ 0.750112] UDP-Lite hash table entries: 256 (order: 0, 4096 bytes)
[ 0.756799] NET: Registered protocol family 1
[ 0.761767] RPC: Registered named UNIX socket transport module.
[ 0.767822] RPC: Registered udp transport module.
[ 0.772557] RPC: Registered tcp transport module.
[ 0.777323] RPC: Registered tcp NFSv4.1 backchannel transport module.
[ 0.785046] hw perfevents: enabled with armv6_1176 PMU driver, 3 counters available
[ 0.794182] futex hash table entries: 256 (order: -1, 3072 bytes)
[ 0.816618] VFS: Disk quotas dquot_6.6.0// VFS information
[ 0.820999] VFS: Dquot-cache hash table entries: 1024 (order 0, 4096 bytes)
[ 0.830680] FS-Cache: Netfs ‘nfs’ registered for caching
[ 0.837438] NFS: Registering the id_resolver key type
[ 0.842616] Key type id_resolver registered
[ 0.846953] Key type id_legacy registered
[ 0.854796] Block layer SCSI generic (bsg) driver version 0.4 loaded (major 252)
[ 0.862778] io scheduler noop registered
[ 0.866779] io scheduler deadline registered (default)
[ 0.872354] io scheduler cfq registered
[ 0.878777] BCM2708FB: allocated DMA memory 5b800000
[ 0.883951] BCM2708FB: allocated DMA channel 0 @ f2007000
[ 0.894517] Console: switching to colour frame buffer device 82x26
[ 0.905754] Serial: 8250/16550 driver, 0 ports, IRQ sharing disabled
[ 0.915513] vc-cma: Videocore CMA driver
[ 0.921209] vc-cma: vc_cma_base = 0x00000000
[ 0.927667] vc-cma: vc_cma_size = 0x00000000 (0 MiB)
[ 0.934745] vc-cma: vc_cma_initial = 0x00000000 (0 MiB)
[ 0.942041] vc-mem: phys_addr:0x00000000 mem_base=0x1ec00000 mem_size:0x20000000(512 MiB)
[ 0.972531] brd: module loaded
[ 0.986428] loop: module loaded
[ 0.992227] vchiq: vchiq_init_state: slot_zero = 0xdb880000, is_master = 0
[ 1.002848] Loading iSCSI transport class v2.0-870.
[ 1.010911] usbcore: registered new interface driver smsc95xx
[ 1.018561] dwc_otg: version 3.00a 10-AUG-2012 (platform bus)
[ 1.226240] Core Release: 2.80a
[ 1.230928] Setting default values for core params
[ 1.237309] Finished setting default values for core params
[ 1.444723] Using Buffer DMA mode
[ 1.449623] Periodic Transfer Interrupt Enhancement - disabled
[ 1.457074] Multiprocessor Interrupt Enhancement - disabled
[ 1.464295] OTG VER PARAM: 0, OTG VER FLAG: 0
[ 1.470287] Dedicated Tx FIFOs mode
[ 1.475872] WARN::dwc_otg_hcd_init:1047: FIQ DMA bounce buffers: virt = 0xdb814000 dma = 0x5b814000 len=9024
[ 1.489017] FIQ FSM acceleration enabled for :
[ 1.489017] Non-periodic Split Transactions
[ 1.489017] Periodic Split Transactions
[ 1.489017] High-Speed Isochronous Endpoints
[ 1.512339] WARN::hcd_init_fiq:412: FIQ on core 0 at 0xc03dd6ac
[ 1.519921] WARN::hcd_init_fiq:413: FIQ ASM at 0xc03dd988 length 36
[ 1.527836] WARN::hcd_init_fiq:438: MPHI regs_base at 0xdc896000
[ 1.535562] dwc_otg 20980000.usb: DWC OTG Controller
[ 1.542176] dwc_otg 20980000.usb: new USB bus registered, assigned bus number 1
[ 1.551213] dwc_otg 20980000.usb: irq 32, io mem 0x00000000
[ 1.558460] Init: Port Power? op_state=1
[ 1.563985] Init: Power Port (0)
[ 1.569081] usb usb1: New USB device found, idVendor=1d6b, idProduct=0002
[ 1.577540] usb usb1: New USB device strings: Mfr=3, Product=2, SerialNumber=1
[ 1.586401] usb usb1: Product: DWC OTG Controller
[ 1.592717] usb usb1: Manufacturer: Linux 4.1.18+ dwc_otg_hcd
[ 1.600031] usb usb1: SerialNumber: 20980000.usb
[ 1.607263] hub 1-0:1.0: USB hub found
[ 1.612757] hub 1-0:1.0: 1 port detected
[ 1.619430] usbcore: registered new interface driver usb-storage
[ 1.627539] mousedev: PS/2 mouse device common for all mice
[ 1.635776] bcm2835-cpufreq: min=700000 max=700000
[ 1.642517] sdhci: Secure Digital Host Controller Interface driver
[ 1.650338] sdhci: Copyright(c) Pierre Ossman
[ 1.656701] sdhost: log_buf @ db813000 (5b813000)
[ 1.742719] mmc0: sdhost-bcm2835 loaded - DMA enabled (>1)
[ 1.750373] sdhci-pltfm: SDHCI platform and OF driver helper
[ 1.778602] ledtrig-cpu: registered to indicate activity on CPUs
[ 1.786572] hidraw: raw HID events driver (C) Jiri Kosina
[ 1.793960] usbcore: registered new interface driver usbhid
[ 1.801132] usbhid: USB HID core driver
[ 1.811110] Initializing XFRM netlink socket
[ 1.817278] Indeed it is in host mode hprt0 = 00021501
[ 1.884554] NET: Registered protocol family 17
[ 1.890968] Key type dns_resolver registered
[ 1.904841] registered taskstats version 1
[ 1.910951] vc-sm: Videocore shared memory driver
[ 1.917563] [vc_sm_connected_init]: start
[ 1.924665] [vc_sm_connected_init]: end - returning 0
[ 1.933842] Waiting for root device /dev/mmcblk0p2…
[ 1.950344] mmc0: host does not support reading read-only switch, assuming write-enable
[ 1.963583] mmc0: new high speed SDHC card at address b368
[ 1.971566] mmcblk0: mmc0:b368 SDC 7.51 GiB
[ 1.980155] mmcblk0: p1 p2
[ 2.052765] usb 1-1: new high-speed USB device number 2 using dwc_otg
[ 2.061925] Indeed it is in host mode hprt0 = 00001101
[ 2.130259] EXT4-fs (mmcblk0p2): mounted filesystem with ordered data mode. Opts: (null)
[ 2.141890] VFS: Mounted root (ext4 filesystem) readonly on device 179:2.
[ 2.159602] devtmpfs: mounted
[ 2.165579] Freeing unused kernel memory: 352K (c0770000 - c07c8000)
[ 2.283253] usb 1-1: New USB device found, idVendor=0424, idProduct=9512
[ 2.292007] usb 1-1: New USB device strings: Mfr=0, Product=0, SerialNumber=0
[ 2.302876] hub 1-1:1.0: USB hub found
[ 2.309261] hub 1-1:1.0: 3 ports detected
[ 2.564499] random: systemd urandom read with 61 bits of entropy available
[ 2.579766] systemd[1]: systemd 215 running in system mode. (+PAM +AUDIT +SELINUX +IMA +SYSVINIT +LIBCRYPTSETUP +GCRYPT +ACL +XZ -SECCOMP -APPARMOR)
[ 2.597128] usb 1-1.1: new high-speed USB device number 3 using dwc_otg // USB information
[ 2.606478] systemd[1]: Detected architecture ‘arm’.
[ 2.713310] usb 1-1.1: New USB device found, idVendor=0424, idProduct=ec00
[ 2.722251] usb 1-1.1: New USB device strings: Mfr=0, Product=0, SerialNumber=0
[ 2.748879] NET: Registered protocol family 10
[ 2.758094] systemd[1]: Inserted module ‘ipv6’
[ 2.765114] smsc95xx v1.0.4
[ 2.777284] systemd[1]: Set hostname to .
[ 2.831806] smsc95xx 1-1.1:1.0 eth0: register ‘smsc95xx’ at usb-20980000.usb-1.1, smsc95xx USB 2.0 Ethernet, b8:27:eb:33:a7:96
[ 2.921707] uart-pl011 20201000.uart: no DMA platform data
[ 3.510755] systemd[1]: Cannot add dependency job for unit display-manager.service, ignoring: Unit display-manager.service failed to load: No such file or directory.
[ 3.537318] systemd[1]: Starting Forward Password Requests to Wall Directory Watch.
[ 3.549967] systemd[1]: Started Forward Password Requests to Wall Directory Watch.
[ 3.561823] systemd[1]: Expecting device dev-ttyAMA0.device…
[ 3.572924] systemd[1]: Starting Remote File Systems (Pre).
[ 3.583543] systemd[1]: Reached target Remote File Systems (Pre).
[ 3.592030] systemd[1]: Starting Encrypted Volumes.
[ 3.601895] systemd[1]: Reached target Encrypted Volumes.
[ 3.609815] systemd[1]: Starting Arbitrary Executable File Formats File System Automount Point.
[ 3.626548] systemd[1]: Set up automount Arbitrary Executable File Formats File System Automount Point.
[ 3.640487] systemd[1]: Starting Swap.
[ 3.649274] systemd[1]: Reached target Swap.
[ 3.655869] systemd[1]: Expecting device dev-mmcblk0p1.device…
[ 3.666639] systemd[1]: Starting Root Slice.
[ 3.675708] systemd[1]: Created slice Root Slice.
[ 3.682457] systemd[1]: Starting User and Session Slice.
[ 3.692893] systemd[1]: Created slice User and Session Slice.
[ 3.700698] systemd[1]: Starting /dev/initctl Compatibility Named Pipe.
[ 3.712171] systemd[1]: Listening on /dev/initctl Compatibility Named Pipe.
[ 3.721334] systemd[1]: Starting Delayed Shutdown Socket.
[ 3.731613] systemd[1]: Listening on Delayed Shutdown Socket.
[ 3.739521] systemd[1]: Starting Journal Socket (/dev/log).
[ 3.749939] systemd[1]: Listening on Journal Socket (/dev/log).
[ 3.758004] systemd[1]: Starting udev Control Socket.
[ 3.767775] systemd[1]: Listening on udev Control Socket.
[ 3.775334] systemd[1]: Starting udev Kernel Socket.
[ 3.784937] systemd[1]: Listening on udev Kernel Socket.
[ 3.792291] systemd[1]: Starting Journal Socket.
[ 3.801797] systemd[1]: Listening on Journal Socket.
[ 3.809032] systemd[1]: Starting System Slice.
[ 3.818276] systemd[1]: Created slice System Slice.
[ 3.825377] systemd[1]: Starting File System Check on Root Device…
[ 3.840897] systemd[1]: Starting system-systemd\x2dfsck.slice.
[ 3.861987] systemd[1]: Created slice system-systemd\x2dfsck.slice.
[ 3.873883] systemd[1]: Starting system-getty.slice.
[ 3.894040] systemd[1]: Created slice system-getty.slice.
[ 3.903948] systemd[1]: Starting system-serial\x2dgetty.slice.
[ 3.916204] systemd[1]: Created slice system-serial\x2dgetty.slice.
[ 3.925608] systemd[1]: Starting Increase datagram queue length…
[ 3.951212] systemd[1]: Starting Restore / save the current clock…
[ 3.988340] systemd[1]: Starting udev Coldplug all Devices…
[ 4.061012] systemd[1]: Started Set Up Additional Binary Formats.
[ 4.116562] systemd[1]: Starting Load Kernel Modules…
[ 4.188874] systemd[1]: Mounting POSIX Message Queue File System…
[ 4.295465] systemd[1]: Mounting Debug File System…
[ 4.320276] systemd[1]: Mounted Huge Pages File System.
[ 4.343804] systemd[1]: Starting Create list of required static device nodes for the current kernel…
[ 4.364861] systemd[1]: Starting Slices.
[ 4.381353] systemd[1]: Reached target Slices.
[ 4.397220] systemd[1]: Started Increase datagram queue length.
[ 4.704288] systemd[1]: Started File System Check on Root Device.
[ 4.733046] systemd[1]: Started Restore / save the current clock.
[ 4.766911] systemd[1]: Started Load Kernel Modules.
[ 4.793010] systemd[1]: Mounted POSIX Message Queue File System.
[ 4.815336] systemd[1]: Mounted Debug File System.
[ 4.842933] systemd[1]: Started Create list of required static device nodes for the current kernel.
[ 4.881438] systemd[1]: Time has been changed
[ 4.939493] systemd[1]: Started udev Coldplug all Devices.
[ 5.196823] systemd[1]: Starting Create Static Device Nodes in /dev…
[ 5.214792] systemd[1]: Mounting Configuration File System…
[ 5.244766] systemd[1]: Starting Apply Kernel Variables…
[ 5.309277] systemd[1]: Mounted FUSE Control File System.
[ 5.339617] systemd[1]: Starting Syslog Socket.
[ 5.380159] systemd[1]: Listening on Syslog Socket.

Raspbian GNU/Linux 8 raspberrypi ttyAMA0

Download

Win32DiskImager-0.9.5-install.exe

Access data with JPA in Spring

Now that you could start up a Spring Web Application, where data persistence will play significant role.
Thus, I will present how to integerate JPA(java persitence api) with Spring.

Gradle build file

First of all, you must finish your Gradle build file which is build.gradle.

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
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:1.3.3.RELEASE")
}
}

apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'idea'
apply plugin: 'spring-boot'

jar {
baseName = 'gs-rest-service'
version = '0.1.0'
}

repositories {
mavenCentral()
}

sourceCompatibility = 1.8
targetCompatibility = 1.8

dependencies {
compile("org.springframework.boot:spring-boot-starter-web")
compile("org.springframework.boot:spring-boot-starter-data-rest")
compile("org.springframework.boot:spring-boot-starter-data-jpa")
compile("mysql:mysql-connector-java:5.1.6")
compile("com.h2database:h2")
testCompile("junit:junit")
}

task wrapper(type: Wrapper) {
gradleVersion = '2.5'
}

In order to access database, which is MySQL that I use, we’d better append mysql connector to this project.
And spring-boot-starter-data-jpa is spring jpa package. The spring-boot-starter-data-rest
would be used later, which would enhance the RESTful data accessing.

Configure JPA

It’s neccessary to connect JPA with database. Of course, JPA would work out even without database. The requirement
of data persistence force us to support with a database. As you know, The MySQL database is my choice. And this setting
is stored in a file which is application.properties. Now let crate a new file.

1
2
3
4
└── src
└── main
└── resources
└── application.properties

And input script below.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#DB properties:
spring.datasource.url=jdbc:mysql://localhost:3306/test
spring.datasource.username=root
spring.datasource.password=password
spring.datasource.driverClassName=com.mysql.jdbc.Driver

#JPA Configuration:
spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=update

#view Configuration:
spring.view.prefix=/WEB-INF/views/

#Server Configuration:
server.port = 90

Make sure you could build this project.

Define a simple entity

In this example, you store Customer objects, annotated as JPA entity.
src/main/java/hello/Customer.java

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
package hello;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

@Entity
public class Customer {

@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private long id;
private String firstName;
private String lastName;

protected Customer() {}

public Customer(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}

@Override
public String toString() {
return String.format(
"Customer[id=%d, firstName='%s', lastName='%s']",
id, firstName, lastName);
}

}

Create simple queries

Spring Data JPA focuses on using JPA to store data in a relational database. Its most
compelling feature is the ability to create repository implementations automatically,
at runtime, from a repository interface.
src/main/java/hello/CustomerRepository.java

1
2
3
4
5
6
7
8
9
10
package hello;

import java.util.List;

import org.springframework.data.repository.CrudRepository;

public interface CustomerRepository extends CrudRepository<Customer, Long> {

List<Customer> findByLastName(String lastName);
}

Enhance the Application Class

Now that we have created a App.java, we should append some code.

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
package hello;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;


@SpringBootApplication
public class App {
private static final Logger log = LoggerFactory.getLogger(App.class);

public static void main(String[] args) {
SpringApplication.run(App.class, args);
}

@Bean
public CommandLineRunner demo(CustomerRepository repository) {
return (args) -> {
// save a couple of customers
repository.save(new Customer("Jack", "Bauer"));
repository.save(new Customer("Chloe", "O'Brian"));
repository.save(new Customer("Kim", "Bauer"));
repository.save(new Customer("David", "Palmer"));
repository.save(new Customer("Michelle", "Dessler"));

// fetch all customers
log.info("Customers found with findAll():");
log.info("-------------------------------");
for (Customer customer : repository.findAll()) {
log.info(customer.toString());
}
log.info("");

// fetch an individual customer by ID
Customer customer = repository.findOne(1L);
log.info("Customer found with findOne(1L):");
log.info("--------------------------------");
log.info(customer.toString());
log.info("");

// fetch customers by last name
log.info("Customer found with findByLastName('Bauer'):");
log.info("--------------------------------------------");
for (Customer bauer : repository.findByLastName("Bauer")) {
log.info(bauer.toString());
}
log.info("");
};
}
}

Build and run the project!

Database Result

You should see something like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
== Customers found with findAll():
Customer[id=1, firstName='Jack', lastName='Bauer']
Customer[id=2, firstName='Chloe', lastName='O'Brian']
Customer[id=3, firstName='Kim', lastName='Bauer']
Customer[id=4, firstName='David', lastName='Palmer']
Customer[id=5, firstName='Michelle', lastName='Dessler']

== Customer found with findOne(1L):
Customer[id=1, firstName='Jack', lastName='Bauer']

== Customer found with findByLastName('Bauer'):
Customer[id=1, firstName='Jack', lastName='Bauer']
Customer[id=3, firstName='Kim', lastName='Bauer']


As you could see, a new table whose name is customer has been created.
And data has been stored successfully.

Refernce

https://spring.io/guides/gs/accessing-data-jpa/

Download

spring-demo-jpa.rar