- Import assignment 1 files and repo - Assignment 2 codetags/v2.0
@@ -0,0 +1,18 @@ | |||
# General | |||
doc/ | |||
hex/ | |||
micro2019/ | |||
deliver/ | |||
# Eclipse-Atollic related | |||
.project | |||
.cproject | |||
.settings/ | |||
*.ld | |||
Debug/ | |||
Release/ | |||
# Keil related | |||
Keil/ | |||
*.gz | |||
*.zip |
@@ -0,0 +1,9 @@ | |||
[submodule "assignment_1/report/config"] | |||
path = assignment_1/report/config | |||
url = https://git.hoo2.net/hoo2/LaTeX_confing.git | |||
[submodule "assignment_2/report/config"] | |||
path = assignment_2/report/config | |||
url = https://git.hoo2.net/hoo2/LaTeX_confing.git | |||
[submodule "assignment_2/Libraries/STM32CubeF4"] | |||
path = assignment_2/Libraries/STM32CubeF4 | |||
url = https://github.com/hoo2/STM32CubeF4.git |
@@ -0,0 +1,121 @@ | |||
/*! | |||
* @file | |||
* main.c | |||
* @brief | |||
* A palindrome implementation and testing application | |||
* for A.U.TH. Microprocessors and peripherals Lab. | |||
* | |||
* Created on: May 1, 2020 | |||
* Author: Christos Choutouridis AEM: 8997 | |||
* email : <cchoutou@ece.auth.gr> | |||
*/ | |||
#include <stdint.h> | |||
/*! | |||
* The RAM address to use for palindrome result. | |||
* @note: | |||
* Select a RAM location above `__initial_sp`. See your startup_xx.s for details. | |||
* Keil's RAM layout is: | |||
* | |||
* RAM: |<-Heap_Size-><-Stack_Size->|<- WASTED RAM SPACE ->| | |||
* ^ ^ ^ | |||
* | | | | |||
* Start:0x20000000 __initial_sp End of RAM | |||
* | |||
*/ | |||
#define RESULT 0x20001000 | |||
/*! | |||
* String length calculation. | |||
* @arg src{R0} Pointer to string | |||
* @return {R0} String length, -1 if src is NULL | |||
*/ | |||
__asm uint32_t strLength (const char* src) { | |||
// R0: length, return value | |||
// R1: src | |||
// R2: v = *src | |||
MOV R1, R0 // Get variable | |||
CMP R1, #0 // if (src{R1} == NULL) | |||
MOVEQ R0, #-1 // return -1; | |||
BXEQ LR | |||
MOV R0, #0 // length{R0} =0; | |||
len_loop // do { | |||
LDRB R2, [R1], #1 // v{R2} = *src++; | |||
CMP R2, #0 // if(v) | |||
ADDNE R0, R0, #1 // ++length{R0}; | |||
BNE len_loop // } while (v); | |||
BX LR // return length; | |||
} | |||
/*! | |||
* A string palindrome predicate. | |||
* @note | |||
* We use a simple O(n), no stack algorithm. | |||
* @note | |||
* This function also writes to RAM address @ref RESULT the return value (which is nasty). | |||
* @arg src{R0} Pointer to string | |||
* @return {R0} True if palindrome, false if not or src is NULL pointer | |||
* @note | |||
* We consider an empty string "" to be a palindrome, as we can see it the same way both | |||
* from the front and the back. | |||
*/ | |||
__asm uint32_t isPalindrome (const char* src) { | |||
// R0: src[] | |||
// R1: i | |||
// R2: j | |||
// R3: v1 = src[i] | |||
// R4: v2 = src[j] | |||
PUSH {R4, LR} | |||
CMP R0, #0 // if (src{R0} == NULL) | |||
BEQ pal_false // return false; | |||
MOV R4, R0 // save R0 | |||
BL strLength // j{R2} = strLength(src) - 1 | |||
SUB R2, R0, #1 | |||
MOV R0, R4 // src{R0} | |||
MOV R1, #0 // i{R1} =0; | |||
pal_loop | |||
CMP R1, R2 // while (i<j) { | |||
BGE pal_true | |||
LDRB R3, [R0, R1] // v1 = *src[i]; | |||
LDRB R4, [R0, R2] // v2 = *src[j]; | |||
CMP R3, R4 // if (v1 == v2) { | |||
ADDEQ R1, R1, #1 // ++i; | |||
SUBEQ R2, R2, #1 // --j; | |||
BEQ pal_loop // // goto loop; | |||
pal_false // } else | |||
MOV R0, #0 // return *RESULT = 0; | |||
LDR R1, =RESULT | |||
STRB R0, [R1] | |||
POP {R4, PC} | |||
// } | |||
pal_true | |||
MOV R0, #1 // return *RESULT = 1; | |||
LDR R1, =RESULT | |||
STRB R0, [R1] | |||
POP {R4, PC} | |||
} | |||
/*! | |||
* Main routine. | |||
* @note | |||
* This routine plays the role of debuging-mode unit testing. | |||
*/ | |||
int main(void) { | |||
const char *s1 = "hello world!"; // Not a palindrome | |||
const char *s2 = "aibohphobia"; // Aibophobia def= "Irational fear of palindromes", palindrome. | |||
const char *s3 = ""; // Empty string, palindrome. | |||
const char *s4 = 0; // NULL pointer. Out of scope, not palindrome | |||
uint32_t res1 = isPalindrome (s1); // Test case 1 | |||
uint32_t res2 = isPalindrome (s2); // Test case 2 | |||
uint32_t res3 = isPalindrome (s3); // Test case 3 | |||
uint32_t res4 = isPalindrome (s4); // Test case 4 | |||
while (1); // Trap forever | |||
//return 0; //!< comment out return, to suppress "statement is unreachable" warning. | |||
//!^ @note: | |||
//! **Weird** Keil's way for "statement is unreachable", suppresion. | |||
} |
@@ -0,0 +1 @@ | |||
Subproject commit ddb6624bbf227f98db5d25ae7b2a5698719fc17b |
@@ -0,0 +1,337 @@ | |||
<?xml version="1.0" encoding="UTF-8" standalone="no"?> | |||
<!-- Created with Inkscape (http://www.inkscape.org/) --> | |||
<svg | |||
xmlns:dc="http://purl.org/dc/elements/1.1/" | |||
xmlns:cc="http://creativecommons.org/ns#" | |||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" | |||
xmlns:svg="http://www.w3.org/2000/svg" | |||
xmlns="http://www.w3.org/2000/svg" | |||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" | |||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" | |||
width="210mm" | |||
height="297mm" | |||
viewBox="0 0 210 297" | |||
version="1.1" | |||
id="svg8" | |||
inkscape:version="0.92.4 (5da689c313, 2019-01-14)" | |||
sodipodi:docname="RAM_layout.svg" | |||
inkscape:export-filename="/home/hoo2/Software/AUTH/Micro/assignement_1/report/images/RAM_layout.svg.png" | |||
inkscape:export-xdpi="600" | |||
inkscape:export-ydpi="600"> | |||
<defs | |||
id="defs2"> | |||
<marker | |||
inkscape:stockid="Arrow2Mstart" | |||
orient="auto" | |||
refY="0.0" | |||
refX="0.0" | |||
id="Arrow2Mstart" | |||
style="overflow:visible" | |||
inkscape:isstock="true"> | |||
<path | |||
id="path4546" | |||
style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1" | |||
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z " | |||
transform="scale(0.6) translate(0,0)" /> | |||
</marker> | |||
<marker | |||
inkscape:stockid="Arrow1Lstart" | |||
orient="auto" | |||
refY="0.0" | |||
refX="0.0" | |||
id="Arrow1Lstart" | |||
style="overflow:visible" | |||
inkscape:isstock="true"> | |||
<path | |||
id="path4522" | |||
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z " | |||
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1" | |||
transform="scale(0.8) translate(12.5,0)" /> | |||
</marker> | |||
<marker | |||
inkscape:stockid="Arrow2Mstart" | |||
orient="auto" | |||
refY="0" | |||
refX="0" | |||
id="Arrow2Mstart-4" | |||
style="overflow:visible" | |||
inkscape:isstock="true"> | |||
<path | |||
inkscape:connector-curvature="0" | |||
id="path4546-8" | |||
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1" | |||
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" | |||
transform="scale(0.6)" /> | |||
</marker> | |||
<marker | |||
inkscape:stockid="Arrow2Mstart" | |||
orient="auto" | |||
refY="0" | |||
refX="0" | |||
id="Arrow2Mstart-4-5" | |||
style="overflow:visible" | |||
inkscape:isstock="true"> | |||
<path | |||
inkscape:connector-curvature="0" | |||
id="path4546-8-2" | |||
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1" | |||
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" | |||
transform="scale(0.6)" /> | |||
</marker> | |||
<marker | |||
inkscape:stockid="Arrow2Mstart" | |||
orient="auto" | |||
refY="0" | |||
refX="0" | |||
id="Arrow2Mstart-6" | |||
style="overflow:visible" | |||
inkscape:isstock="true"> | |||
<path | |||
inkscape:connector-curvature="0" | |||
id="path4546-4" | |||
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1" | |||
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" | |||
transform="scale(0.6)" /> | |||
</marker> | |||
<marker | |||
inkscape:stockid="Arrow2Mstart" | |||
orient="auto" | |||
refY="0" | |||
refX="0" | |||
id="Arrow2Mstart-6-1" | |||
style="overflow:visible" | |||
inkscape:isstock="true"> | |||
<path | |||
inkscape:connector-curvature="0" | |||
id="path4546-4-4" | |||
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1" | |||
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" | |||
transform="scale(0.6)" /> | |||
</marker> | |||
<marker | |||
inkscape:stockid="Arrow2Mstart" | |||
orient="auto" | |||
refY="0" | |||
refX="0" | |||
id="Arrow2Mstart-6-1-1" | |||
style="overflow:visible" | |||
inkscape:isstock="true"> | |||
<path | |||
inkscape:connector-curvature="0" | |||
id="path4546-4-4-7" | |||
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1" | |||
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" | |||
transform="scale(0.6)" /> | |||
</marker> | |||
</defs> | |||
<sodipodi:namedview | |||
id="base" | |||
pagecolor="#ffffff" | |||
bordercolor="#666666" | |||
borderopacity="1.0" | |||
inkscape:pageopacity="0.0" | |||
inkscape:pageshadow="2" | |||
inkscape:zoom="1.4" | |||
inkscape:cx="162.42672" | |||
inkscape:cy="791.2836" | |||
inkscape:document-units="mm" | |||
inkscape:current-layer="layer1" | |||
showgrid="false" | |||
inkscape:snap-page="false" | |||
inkscape:window-width="1920" | |||
inkscape:window-height="1011" | |||
inkscape:window-x="0" | |||
inkscape:window-y="32" | |||
inkscape:window-maximized="1" /> | |||
<metadata | |||
id="metadata5"> | |||
<rdf:RDF> | |||
<cc:Work | |||
rdf:about=""> | |||
<dc:format>image/svg+xml</dc:format> | |||
<dc:type | |||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> | |||
<dc:title></dc:title> | |||
</cc:Work> | |||
</rdf:RDF> | |||
</metadata> | |||
<g | |||
inkscape:label="Layer 1" | |||
inkscape:groupmode="layer" | |||
id="layer1"> | |||
<g | |||
id="g6178" | |||
inkscape:export-xdpi="600" | |||
inkscape:export-ydpi="600"> | |||
<rect | |||
inkscape:export-ydpi="96" | |||
inkscape:export-xdpi="96" | |||
style="fill:none;stroke:#000000;stroke-width:0.5;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" | |||
y="45.689461" | |||
x="21.946363" | |||
height="73.879112" | |||
width="23.566633" | |||
id="rect10" /> | |||
<g | |||
inkscape:export-ydpi="96" | |||
inkscape:export-xdpi="96" | |||
id="g5613"> | |||
<path | |||
style="fill:none;stroke:#000000;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#Arrow2Mstart)" | |||
d="m 47.634183,46.875398 h 5.565965" | |||
id="path4520" | |||
inkscape:connector-curvature="0" /> | |||
<flowRoot | |||
xml:space="preserve" | |||
id="flowRoot4836" | |||
style="font-style:normal;font-weight:normal;font-size:40px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none" | |||
transform="matrix(0.26458333,0,0,0.26458333,2.286756,-2.1733631)"><flowRegion | |||
id="flowRegion4838"><rect | |||
id="rect4840" | |||
width="107.85714" | |||
height="61.07143" | |||
x="197.14285" | |||
y="153.23396" /></flowRegion><flowPara | |||
id="flowPara4842" | |||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.66666698px;font-family:Arial;-inkscape-font-specification:Arial">End of RAM</flowPara></flowRoot> </g> | |||
<g | |||
inkscape:export-ydpi="96" | |||
inkscape:export-xdpi="96" | |||
id="g5613-9" | |||
transform="translate(0,71.746594)"> | |||
<path | |||
style="fill:none;stroke:#000000;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#Arrow2Mstart-6)" | |||
d="m 47.634183,46.875398 h 5.565965" | |||
id="path4520-9" | |||
inkscape:connector-curvature="0" /> | |||
<flowRoot | |||
xml:space="preserve" | |||
id="flowRoot4836-0" | |||
style="font-style:normal;font-weight:normal;font-size:40px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none" | |||
transform="matrix(0.26458333,0,0,0.26458333,2.286756,-2.1733631)"><flowRegion | |||
id="flowRegion4838-8"><rect | |||
id="rect4840-9" | |||
width="107.85714" | |||
height="61.07143" | |||
x="197.14285" | |||
y="153.23396" /></flowRegion><flowPara | |||
id="flowPara4842-3" | |||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.66666698px;font-family:Arial;-inkscape-font-specification:Arial">0x20000000</flowPara></flowRoot> </g> | |||
<path | |||
inkscape:export-ydpi="96" | |||
inkscape:export-xdpi="96" | |||
inkscape:connector-curvature="0" | |||
id="path5765" | |||
d="M 21.878451,112.45039 H 45.302185" | |||
style="fill:none;stroke:#000000;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" /> | |||
<flowRoot | |||
inkscape:export-ydpi="96" | |||
inkscape:export-xdpi="96" | |||
transform="matrix(0.26458333,0,0,0.26458333,-21.166366,67.028655)" | |||
style="font-style:normal;font-weight:normal;font-size:40px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none" | |||
id="flowRoot4836-0-6-7" | |||
xml:space="preserve"><flowRegion | |||
id="flowRegion4838-8-7-1"><rect | |||
y="153.23396" | |||
x="197.14285" | |||
height="66.627274" | |||
width="98.260719" | |||
id="rect4840-9-7-2" /></flowRegion><flowPara | |||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.66666698px;font-family:Arial;-inkscape-font-specification:Arial" | |||
id="flowPara4842-3-3-2">data</flowPara></flowRoot> <path | |||
inkscape:export-ydpi="96" | |||
inkscape:export-xdpi="96" | |||
inkscape:connector-curvature="0" | |||
id="path5765-1" | |||
d="M 21.949511,106.23637 H 45.302186" | |||
style="fill:none;stroke:#000000;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" /> | |||
<flowRoot | |||
inkscape:export-ydpi="96" | |||
inkscape:export-xdpi="96" | |||
transform="matrix(0.26458333,0,0,0.26458333,-20.665449,60.530144)" | |||
style="font-style:normal;font-weight:normal;font-size:40px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none" | |||
id="flowRoot4836-0-6-7-5" | |||
xml:space="preserve"><flowRegion | |||
id="flowRegion4838-8-7-1-0"><rect | |||
y="153.23396" | |||
x="197.14285" | |||
height="66.627274" | |||
width="98.260719" | |||
id="rect4840-9-7-2-9" /></flowRegion><flowPara | |||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.66666698px;font-family:Arial;-inkscape-font-specification:Arial" | |||
id="flowPara4842-3-3-2-0">bss</flowPara></flowRoot> <flowRoot | |||
inkscape:export-ydpi="96" | |||
inkscape:export-xdpi="96" | |||
transform="matrix(0.26458333,0,0,0.26458333,-25.394187,54.279243)" | |||
style="font-style:normal;font-weight:normal;font-size:40px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none" | |||
id="flowRoot4836-0-6-7-5-3" | |||
xml:space="preserve"><flowRegion | |||
id="flowRegion4838-8-7-1-0-7"><rect | |||
y="153.23396" | |||
x="197.14285" | |||
height="66.627274" | |||
width="98.260719" | |||
id="rect4840-9-7-2-9-4" /></flowRegion><flowPara | |||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.66666698px;font-family:Arial;-inkscape-font-specification:Arial" | |||
id="flowPara4842-3-3-2-0-1">Heap_Size</flowPara></flowRoot> <flowRoot | |||
inkscape:export-ydpi="96" | |||
inkscape:export-xdpi="96" | |||
transform="matrix(0.26458333,0,0,0.26458333,-25.498918,39.763973)" | |||
style="font-style:normal;font-weight:normal;font-size:40px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none" | |||
id="flowRoot4836-0-6-7-5-3-1" | |||
xml:space="preserve"><flowRegion | |||
id="flowRegion4838-8-7-1-0-7-3"><rect | |||
y="153.23396" | |||
x="197.14285" | |||
height="66.627274" | |||
width="98.260719" | |||
id="rect4840-9-7-2-9-4-0" /></flowRegion><flowPara | |||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.66666698px;font-family:Arial;-inkscape-font-specification:Arial" | |||
id="flowPara4842-3-3-2-0-1-3">Stack_Size</flowPara></flowRoot> <path | |||
inkscape:export-ydpi="96" | |||
inkscape:export-xdpi="96" | |||
inkscape:connector-curvature="0" | |||
id="path5765-1-2" | |||
d="M 21.949511,86.278273 H 45.302186" | |||
style="fill:none;stroke:#000000;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" /> | |||
<g | |||
inkscape:export-ydpi="96" | |||
inkscape:export-xdpi="96" | |||
id="g5915-5" | |||
transform="translate(0,-17.859523)"> | |||
<path | |||
style="fill:none;stroke:#000000;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#Arrow2Mstart-6-1-1)" | |||
d="m 47.634183,105.0463 h 5.565965" | |||
id="path4520-9-9-6" | |||
inkscape:connector-curvature="0" /> | |||
<flowRoot | |||
xml:space="preserve" | |||
id="flowRoot4836-0-6-5" | |||
style="font-style:normal;font-weight:normal;font-size:40px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none" | |||
transform="matrix(0.26458333,0,0,0.26458333,2.286756,55.997509)"><flowRegion | |||
id="flowRegion4838-8-7-4"><rect | |||
id="rect4840-9-7-22" | |||
width="107.85714" | |||
height="61.07143" | |||
x="197.14285" | |||
y="153.23396" /></flowRegion><flowPara | |||
id="flowPara4842-3-3-1" | |||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.66666698px;font-family:Arial;-inkscape-font-specification:Arial">__initial_sp</flowPara></flowRoot> </g> | |||
<flowRoot | |||
inkscape:export-ydpi="96" | |||
inkscape:export-xdpi="96" | |||
transform="matrix(0.26458333,0,0,0.26458333,-21.392364,17.854437)" | |||
style="font-style:normal;font-weight:normal;font-size:40px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none" | |||
id="flowRoot4836-0-6-7-5-3-7" | |||
xml:space="preserve"><flowRegion | |||
id="flowRegion4838-8-7-1-0-7-2"><rect | |||
y="153.23396" | |||
x="197.14285" | |||
height="66.627274" | |||
width="98.260719" | |||
id="rect4840-9-7-2-9-4-4" /></flowRegion><flowPara | |||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.66666698px;font-family:Arial;-inkscape-font-specification:Arial" | |||
id="flowPara4842-3-3-2-0-1-1">Free</flowPara></flowRoot> </g> | |||
</g> | |||
</svg> |
@@ -0,0 +1 @@ | |||
<mxfile host="app.diagrams.net" modified="2020-05-03T15:08:08.336Z" agent="5.0 (X11)" etag="FJrRoutRW1H6xKy9lX6Y" version="13.0.6" type="device"><diagram id="C5RBs43oDa-KdzZeNtuy" name="Page-1">7Vtbc+I2FP41zLSdYceSLyGPIZfdtjTT5to8KlgxzgqLlQWB/vpKtnyTDHgTwCQhM5lYx5IsnXO+7xxd0rFPx/OvDE1Gf1Efkw60/HnHPutACEDPFX+kZJFKPFsJAhb6qlIhuA7/w0poKek09HFcqcgpJTycVIVDGkV4yCsyxBh9qVZ7oqT61QkKsCG4HiJiSu9Dn49SaQ8eFfJvOAxG2ZeBd5y+GaOssppJPEI+fSmJ7POOfcoo5enTeH6KiVReppf73xf3ZPDd+/rHP/EPdNv/8+byrpt2dvEzTfIpMBzxV3c9H0b88f7h7vLqidyh2zk9WQy6wFFz44tMYdgX+lNFyviIBjRC5LyQ9hmdRj6W3VqiVNQZUDoRQiCEz5jzhXIGNOVUiEZ8TNRbPA/5v7L5F1eVHkpvzuaq56SwyAoRZ4tSI1l8KL8rmiWlrF06PzkpzR/WKFPVi+mUDfGKep7yacQCvLI/mLuMwBqmYyxGKRoyTBAPZ9XRIeX0QV6vMKx4ULb9CTs7Vpt2BiUrFzZfY2dQsXJh9P2xcz2iem+0s2r6Nw3FuKGliNjNLKho2O1Z1S7SgalWhbecMIYWpWoTWSFe8R1Y/U7GfhcN62fhoXDWdASF6+Y6aeTNq2wxQ2Sq9BmzoRDIZ1m0Lm8HA8Ph2YiOH6dCD/2XUcjx9QQlBn8Rca/qtjnRS796ohG/QOOQyAl+w2SGeThE6oXyfIFtu49IGESiMBT+hpnshjP6PQ86Scfik2EUiJJXlG4SMHWd3IebuuwMM47nJX8ynS5761aNBI5V+aWIiCBzsFEpGnqak22Mj0CrfPQR4g7Ikql1hPRWPmpq55WjLEG1Az0ixtv3w5l4DHiiq1QkISVzPKRm7v2YyuSqX8AuF2VNZ0DhXqhMcIDblyOSIvcs61UMPO24+jEh3tAQoDmE5zVD0Kkp92ywnp504gkIimPldTWcUyazbRGMDY++uBWKcYBrUozlmhTjbo1i7APFvJFiYNOcp1WKgQbFhDkgrQyBj0xHegn8zwWAORvgKOCjXwSUf5UTqyeLD4ZfPUGAvbYTBPuA3ubordWgZYJ3eTLd1rrUMrDbx0EYmbYnJJzEeD24lnh+U70uR8iRlkKDGoRYNQjZXnxz20TIq5b0VqetJf3ysNVk62ZX8a12lLB3YMKN27le00dt2rnRSinJbKCHxpL2VGYiFxvNspR3sgGyffZ2rIbsre+ybQ7VreY3H4G9e00XJ60mONA7sPeO7Lyrja5Voyyx9wx0ku3oGTwQcWmjSNsmqtuJBrtcaMJW0+gqQK2VAN16mvRWoqw/IYLaCZGtm3JDJ1dOz639zqZOolboTMvahKVkoqZvPHW7zyYT7HTjaPN4djwtsTo2t33dXa6K7aNW4fyavKq9g+4VcbRBwLWdNgMuMCMuw3zKROA7EeIra9Ue8G9X59e3g5tylQ8GTFs/l687j4E1yHS2FmjNvb4HHBuKF3rgWhKUaPCUEipymbOIRhKyTyEhmshIe6RWRYZETtSLcej7ZNkeYpUDtmUWqC9EoZn/1O2zw61Zxdx2+HxWcTSwuDXbAzu1ir1HSen7XDVm9zv3PIplw1wfxcD6KAYMp3nvUQxo6aVbQ5e7jWK2GcUu6Sejy/xudxbEemZusVu6NIPYpzOKrWUWrtt2DHMMo9QcaJxHfsPTi707AvZaPwK263YfSiq2MsctLq0R/MTNK2z6cmgufi0xF6uhbd4OrWRc+wksLTnMY9K6uzHbQ5a59K1B1h1iIXoUyoNWV6YSOAhjwV7x6vuPJVF3+c/yW1VrexUpTZLaJDe2m7YBaZuweQuYtlh6NGq2sNMWs6V3vswmjmoCm+vjEwMH2g2BA7aGHOew2pWX+/TLurDt9a5j5gqfLoHTs2q4vQROFIt/W0yPQop//rTP/wc=</diagram></mxfile> |
@@ -0,0 +1,119 @@ | |||
% | |||
% Report description | |||
% | |||
% authors: | |||
% Χρήστος Χουτουρίδης ΑΕΜ 8997 | |||
% cchoutou@ece.auth.gr | |||
% Document configuration | |||
\newcommand{\ClassName}{Μικροεπεξεργαστές και Περιφερειακά} | |||
\newcommand{\DocTitle}{1η Εργασία} | |||
\newcommand{\InstructorName}{Παπαευσταθίου Ιωάννης} | |||
\newcommand{\InstructorMail}{ygp@ece.auth.gr} | |||
\newcommand{\CurrentDate}{\today} | |||
\input{config/AuthReportConfig.tex} | |||
%\renewcommand{\AuthorName}{Χρήστος Χουτουρίδης} | |||
%\renewcommand{\AuthorMail}{cchoutou@ece.auth.gr} | |||
%\renewcommand{\AuthorAEM}{8997} | |||
\setFancyHeadLR{\ClassName}{\DocTitle} | |||
%\setFancyHeadLERO{\ClassName}{\DocTitle} | |||
% Document | |||
% ================= | |||
\begin{document} | |||
\FirstPage | |||
%\tableofcontents | |||
%\listoffigures | |||
%\listoftables | |||
\section{Εισαγωγή} | |||
Στην παρούσα εργασία το ζητούμενο είναι η υλοποίηση μιας ρουτίνας σε γλώσσα \eng{assemblly ARM,} που να ελέγχει αν ένα αλφαριθμητικό είναι παλίνδρομο, αλλά και η ενσωμάτωση αυτής σε ένα πρόγραμμα σε γλώσσα \eng{C.} | |||
Για την εργασία χρησιμοποιήσαμε το εργαλείο \eng{Keil uVision} και μιας και δεν αντιμετωπίσαμε κάποιο ιδιαίτερο πρόβλημα, η αναφορά αυτή θα αναλωθεί κυρίως στην υλοποίηση και τον έλεγχο του προγράμματος. | |||
Τον κώδικα της εργασίας αλλά και της παρούσας αναφοράς μπορείτε να βρείτε ακόμα στο προσωπικό \href{https://git.hoo2.net/hoo2/micro_assign_1}{αποθετήριο της εργασίας}. | |||
\section{Παραδοτέα} | |||
Στο παραδοτέο \eng{.zip} αρχείο μπορείτε να βρείτε: | |||
\begin{itemize} | |||
\item Το αρχείο \textbf{\eng{main.c}} που περιέχει όλο τον ζητούμενο κώδικα της εργασίας. | |||
\item Το αρχείο \textbf{\eng{report.pdf}} που είναι παρούσα αναφορά. | |||
\item Τον κατάλογο \textbf{\eng{Keil}} που περιέχει το \eng{project} στο \eng{Keil} που χρησιμοποιήσαμε.\\ | |||
Στο \eng{project} αυτό περιέχονται επιπλέων οι ρυθμίσεις καθώς και τα αρχεία από τη βιβλιοθήκη \eng{CMSIS} που χρειάστηκαν για την ορθή αρχικοποίηση και αλληλεπίδραση με τον επεξεργαστή. | |||
\end{itemize} | |||
\section{Υλοποίηση} | |||
Η υλοποίηση του ελέγχου αν ένα αλφαριθμητικό είναι παλίνδρομο έγινε σε δύο συναρτήσεις, την \eng{\textit{isPalindrome()}} και την \eng{\textit{strLength()},} που λειτουργεί ως βοηθητική συνάρτηση. | |||
Οι συναρτήσεις αυτές είναι υλοποιημένες σε γλώσσα \eng{assemblly} αλλά η κλήση τους από το κυρίως πρόγραμμα δεν διαφέρει καθόλου από την κλήση μιας οποιασδήποτε άλλης συνάρτησης σε γλώσσα \eng{C.} | |||
Για τον λόγο αυτό δεν θα ασχοληθούμε περαιτέρω με το κύριο πρόγραμμα (συνάρτηση \eng{main).} | |||
\subsection{Συνάρτηση \eng{\textit{isPalindrome()}}} | |||
\WrapFigure{0.42}{r}{fig:isPalindrome}{isPalindrome.png}{Διάγραμμα ροής της συνάρτησης \eng{\textit{isPalindrome()}}} | |||
Για τη συνάρτηση αυτή χρησιμοποιήσαμε ένα απλό \eng{O(n)} σειριακό αλγόριθμο, ο οποίος απαιτεί το μήκος του αλφαριθμητικού εισόδου προτού εισέλθει στον κύριο βρόχο επανάληψης. | |||
Για να βρούμε το μήκος χρησιμοποιούμε μια ξεχωριστή συνάρτηση. | |||
Αυτή την υλοποιήσαμε από την αρχή ώστε να μην χρειαστεί να χρησιμοποιηθεί η συνάρτηση \eng{\textit{strlen()}} της \eng{\textit{libc}.} | |||
\par Όπως φαίνεται και στο διάγραμμα του σχήματος \ref{fig:isPalindrome}, στον κύριο βρόχο της συνάρτησης χρησιμοποιούμε δύο απαριθμητές \eng{i, j} χρησιμοποιώντας τους καταχωρητές \eng {R1, R2} αντίστοιχα και ένα δείκτη στη διεύθυνση του αλφαριθμητικού χρησιμοποιώντας τον καταχωρητή \eng{R0.} | |||
Ο ένας δείκτης εκκινεί από την αρχή του αλφαριθμητικού και ο άλλος από το τέλος. | |||
Σε κάθε επανάληψη διαβάζουμε από το αλφαριθμητικό τα \eng{src[i]} και \eng{src[j]} και ελέγχουμε αν είναι ίσα. | |||
Αν δεν είναι τότε το αλφαριθμητικό δεν είναι παλίνδρομο. | |||
Αν είναι τότε μεταθέτουμε το \eng{i} μία θέση δεξιά και το \eng{j} μία θέση αριστερά και επανεκτελούμε τον βρόχο. | |||
Ο βρόχος συνεχίζει όσο το \eng{i} είναι μικρότερο από το \eng{j.} | |||
Αν το \eng{i} γίνει ίσο ή μεγαλύτερο από το \eng{j,} τότε ο βρόχος τερματίζει. | |||
Σε αυτή την περίπτωση το αλφαριθμητικό είναι παλίνδρομο. | |||
\par Αν το αλφαριθμητικό έχει μηδενικό μήκος, τότε ο βρόχος δεν θα εκτελεστεί ούτε μία φορά και η συνάρτηση θα επιστρέψει ότι το αλφαριθμητικό είναι παλίνδρομο. | |||
Έχουμε κάνει δηλαδή την θεώρηση ότι \textbf{\textit{τα μηδενικού μήκους αλφαριθμητικά είναι παλίνδρομα}}, καθώς είναι τα ίδια είτε τα κοιτάς από μπροστά είτε τα κοιτάς από πίσω. | |||
Στην περίπτωση που η είσοδος της συνάρτησης είναι εκτός πεδίου ορισμού, δηλαδή ο \eng{NULL pointer,} τότε η συνάρτηση επιστρέφει ψευδές αποτέλεσμα. | |||
Ο έλεγχος του δείκτη εισόδου γίνεται στην αρχή της συνάρτησης πριν καν γίνει η κλήση για το μήκος, προστατεύοντας έτσι κάποιο \eng{exception} από το \eng{dereference} του δείκτη στην εντολή \eng{LDR.} | |||
\subsection{Συνάρτηση \eng{\textit{strLength()}}} | |||
Η υλοποίηση της \eng{\textit{strLength()}} είναι επίσης ένας σειριακός αλγόριθμος. | |||
Εδώ χρησιμοποιούμε τον καταχωρητή \eng{R1} ώς δείκτη στο αλφαριθμητικό και με αυτόν κάνουμε ανάγνωση της μνήμης, αυξάνοντάς τον ταυτόχρονα μετά από κάθε ανάγνωση. | |||
Η συνάρτηση επιστρέφει τον αριθμό των αναγνώσεων που χρειάστηκαν μέχρι να λάβουμε το νούμερο '0', το οποίο σηματοδοτεί το τέλος του αλφαριθμητικού. | |||
\par Ομοίως και εδώ κάνουμε έλεγχο της εισόδου ώστε αυτή να μην είναι ο \eng{NULL pointer.} | |||
Φυσικά αυτό στη δική μας περίπτωση δεν είναι απαραίτητο καθώς υπάρχει ο αντίστοιχος έλεγχος στην \eng{\textit{isPalindrome()}} προτού την κλήση. | |||
Παρόλα αυτά το θεωρούμε καλή πρακτική, καθώς αυτό καθιστά την \eng{\textit{strLength()}} πιο ολοκληρωμένη συνάρτηση και μια χρήση της στο μέλλον δεν θα προκαλέσει εκπλήξεις. | |||
\subsection{Εγγραφή του αποτελέσματος στη μνήμη} | |||
\WrapFigure{0.23}{l}{fig:ram_layout}{RAM_layout.png}{Διάταξη της μνήμης} | |||
Η συνάρτηση \eng{\textit{isPalindrome()}} αφού εκτελεστεί, επιστρέφει μια τιμή στον \eng{caller.} | |||
Στα ζητούμενα όμως της εργασίας ήταν η συνάρτηση αυτή να γράφει το αποτέλεσμα και σε μία θέση μνήμης της επιλογής μας. | |||
Αυτό υπό κανονικές συνθήκες είναι ανεπίτρεπτο. | |||
Για τα πλαίσια όμως της εργασίας προσπαθήσαμε να ανταπεξέλθουμε με ένα σχετικά ασφαλή τρόπο. | |||
\par Όπως φαίνεται και στο σχήμα \ref{fig:ram_layout}, o συνδέτης \eng{(linker)} του εργαλείου \eng{keil} δεν τοποθετεί τον \eng{SP} στο τέλος της μνήμης. | |||
Για την ακρίβεια, χρησιμοποιώντας δύο τιμές από το \eng{configuration} του \eng{startup} αρχείου για το μέγεθος του σωρού και της στοίβας, υπολογίζει τη τιμή \eng{\textit{\textbf{\_\_initial\_sp}}.} | |||
Αυτή την τιμή χρησιμοποιεί έπειτα σαν πρώτο όρισμα στο \eng{vector table} και άρα αυτή την τιμή έχει ο \eng{SP} κατά την εκκίνηση. | |||
\par Έχοντας αυτό σαν δεδομένο μπορούμε να επιλέξουμε μια τιμή στην ελεύθερη περιοχή, έχοντας πάντα στο μυαλό μας ότι αλλάζοντας τα δεδομένα του προγράμματος η τιμή αυτή μπορεί να αλλάξει. | |||
Στη δική μας περίπτωση η επιλεγμένη τιμή ήταν το \eng{\textbf{0x20001000}.} | |||
Φυσικά αυτή η τιμή μπορεί να αλλάξει εύκολα αλλάζοντας απλώς την τιμή από το \eng{\textbf{\#define RESULT}.} | |||
Μάλιστα αυτό είναι και κάτι που προτρέπουμε κάνει ο οποιονδήποτε θέλει να τρέξει τον κώδικά μας, ώστε να βεβαιωθεί πως η τιμή αυτή είναι στην ασφαλή ζώνη. | |||
\section{Έλεγχος} | |||
Για τον έλεγχο της ορθότητας του κώδικα χρησιμοποιήσαμε τον \eng{debuger} του εργαλείου κάνοντας ταυτόχρονη χρήση του \eng{simulator.} | |||
Καθώς η εκφώνηση ανέφερε την δημιουργία μιας \eng{main,} θεωρήσαμε ότι είναι ευκαιρία να χρησιμοποιήσουμε την \eng{main} για να επιτύχουμε ένα είδους \eng{debug-mode unit testing.} | |||
Έτσι στο εσωτερικό της δηλώσαμε αλφαριθμητικά για έλεγχο και για αυτά καλέσαμε την \eng{\textit{isPalindrome()}.} | |||
Έπειτα εκτελώντας τον \eng{debuger} καταφέραμε να κάνουμε την όποια αποσφαλμάτωση που χρειάστηκε. | |||
\section{Επίλογος} | |||
Θεωρούμε ότι η παρούσα εργασία ήταν μια καλή πρώτη επαφή με την μίξη κώδικα \eng{C - assemblly,} καθώς και των όποιων απαιτήσεων από μεριάς \eng{assemblly} ώστε αυτή να είναι συμβατή με το πρότυπο που ακολουθεί ο \eng{compiler (AAPCS).} | |||
Η μόνη παραφωνία σε αυτή τη συνεργασία ήταν η επιλογή μιας ελεύθερης θέσης μνήμης για την επιστροφή του αποτελέσματος. | |||
Αυτό γιατί μέχρι τη σύνταξη του παρόντος δεν βρήκαμε τρόπο να διαβάσουμε από διαφορετικό αρχείο(πχ το \eng{main.c}) την τιμή \eng{\_\_initial\_sp,} ώστε η επιλογή της θέσης να αυτοματοποιηθεί. | |||
% References | |||
% ============================ | |||
%\begin{thebibliography}{100} | |||
% | |||
%\bibitem{item}item... | |||
%\end{thebibliography} | |||
\end{document} |
@@ -0,0 +1 @@ | |||
Subproject commit e00530150fa6d390ff68bd6fafe6c611c39d8cd7 |
@@ -0,0 +1 @@ | |||
Subproject commit ddb6624bbf227f98db5d25ae7b2a5698719fc17b |
@@ -0,0 +1,289 @@ | |||
/*! | |||
* \file | |||
* NUCLEO_F401RE.h | |||
* \brief | |||
* Nucleo F401RE port file. This file contain the implementation of driver | |||
* calls for F401RE board. | |||
* | |||
* Created on: May 23, 2020 | |||
* Author: Christos Choutouridis AEM: 8997 | |||
* email : <cchoutou@ece.auth.gr> | |||
*/ | |||
#include "NUCLEO_F401RE.h" | |||
/* | |||
* =============== System =============== | |||
*/ | |||
static clock_t volatile __ticks; //!< CPU time | |||
static time_t volatile __now; //!< Time in UNIX seconds past 1-Jan-70 | |||
static clock_t volatile __sys_freq; //!< The CPU's time frequency (SysTick freq) | |||
/*! | |||
* \brief | |||
* This is the SysTick ISR, micro-system time base service for CPU time. | |||
* \note | |||
* This service implements the SysTick callback function in order | |||
* to provide micro system - os like functionalities to an application | |||
* without RTOS | |||
*/ | |||
void SysTick_Handler(void) { | |||
// Time | |||
++__ticks; | |||
if ( !(__ticks % __sys_freq ) ) | |||
++__now; // Do not update __now when we have external time system | |||
} | |||
/*! | |||
* \brief This function configures the source of the time base. | |||
* The time source is configured to have 1ms time base with a dedicated | |||
* Tick interrupt priority. | |||
* \param sf Tick interrupt frequency. | |||
* \retval HAL status | |||
*/ | |||
__weak HAL_StatusTypeDef HAL_SysTick_Init(clock_t sf) { | |||
SystemCoreClockUpdate (); | |||
/* Configure the SysTick to have interrupt in sf time basis */ | |||
if (SysTick_Config (SystemCoreClock/sf) != 0) | |||
return HAL_ERROR; | |||
__sys_freq = sf; | |||
/*Configure the SysTick IRQ priority */ | |||
NVIC_SetPriority (SysTick_IRQn, 3U); | |||
/* Return function status */ | |||
return HAL_OK; | |||
} | |||
/*! | |||
* Select the system frequency without calling the Setting functionality | |||
* \param sf The desired value | |||
* \return The desired value (enable chaining) | |||
*/ | |||
__INLINE clock_t HAL_SelectSysTickFreq (clock_t sf){ | |||
return __sys_freq =sf; | |||
} | |||
/*! | |||
* \brief Get the __sys_freq. | |||
*/ | |||
__INLINE clock_t HAL_GetSysTickFreq (void){ | |||
return __sys_freq; | |||
} | |||
/*! | |||
* \brief Reconfigure the SysTick and update __sys_freq | |||
* \param sf Tick interrupt frequency (CPU time) | |||
* \return status of the operation | |||
* \arg 0 Success | |||
* \arg 1 Fail | |||
*/ | |||
int HAL_SetSysTickFreq (clock_t sf) { | |||
/*Configure the SysTick to have interrupt in sf time basis*/ | |||
if (__sys_freq != sf) { | |||
// Time base configuration | |||
SystemCoreClockUpdate (); | |||
if (SysTick_Config ( (SystemCoreClock>>3)/sf) != 0) | |||
return 1; | |||
else { | |||
__sys_freq = sf; | |||
return 0; | |||
} | |||
} | |||
return 0; | |||
} | |||
// Take over control of SysTick from HAL library | |||
//! disable HAL_InitTick implementation | |||
HAL_StatusTypeDef | |||
HAL_InitTick(uint32_t TickPriority) { return HAL_OK; } | |||
//! Chain GetTick to our implementation | |||
uint32_t HAL_GetTick(void) { return clock(); } | |||
/*! | |||
* \brief This function provides minimum delay (in CPU time) based | |||
* on variable incremented. | |||
* \param Delay specifies the delay time length, in CPU time. | |||
* \note | |||
* uint32_t is implicitly convertible to clock_t and vice versa. | |||
*/ | |||
void HAL_Delay(uint32_t Delay) { | |||
uint32_t tickstart = clock(); | |||
while((clock() - tickstart) < Delay) | |||
; | |||
} | |||
/* | |||
* ======== OS like Functionalities ============ | |||
*/ | |||
//! SysTick frequency getter | |||
__INLINE clock_t get_freq (void) { | |||
return __sys_freq; | |||
} | |||
//! SysTick frequency setter | |||
//! \return True on failure | |||
int set_freq (clock_t sf) { | |||
return HAL_SetSysTickFreq (sf); | |||
} | |||
/*! | |||
* \brief | |||
* determines the processor time. | |||
* \return | |||
* the implementation's best approximation to the processor time | |||
* used by the program since program invocation. The time in | |||
* seconds is the value returned divided by the value of the macro | |||
* CLK_TCK or CLOCKS_PER_SEC | |||
*/ | |||
__INLINE clock_t clock (void) { | |||
return (clock_t) __ticks; | |||
} | |||
/*! | |||
* \brief | |||
* Set the processor time used. | |||
* \param c The new CPU time value | |||
* \return | |||
* The implementation's best approximation to the processor time | |||
* used by the program since program invocation. The time in | |||
* seconds is the value returned divided by the value of the macro | |||
* CLK_TCK or CLOCKS_PER_SEC | |||
*/ | |||
clock_t setclock (clock_t c) { | |||
return __ticks = c; | |||
} | |||
/*! | |||
* \brief | |||
* determines the current calendar time. The encoding of the value is | |||
* unspecified. | |||
* \return | |||
* The implementations best approximation to the current calendar | |||
* time. If timer is not a null pointer, the return value | |||
* is also assigned to the object it points to. | |||
*/ | |||
time_t time (time_t *timer) { | |||
if (timer) | |||
*timer = (time_t)__now; | |||
return (time_t)__now; | |||
} | |||
/*! | |||
* \brief | |||
* Sets the system's idea of the time and date. The time, | |||
* pointed to by t, is measured in seconds since the Epoch, 1970-01-01 | |||
* 00:00:00 +0000 (UTC). | |||
* \param t Pointer to new system's time and date. | |||
* \return On success, zero is returned. On error, -1 is returned | |||
*/ | |||
int settime (const time_t *t) { | |||
if (t) { | |||
__now = *t; | |||
return 0; | |||
} | |||
else | |||
return -1; | |||
} | |||
/* | |||
* ============== Cycle count ============== | |||
*/ | |||
/*! | |||
* Initialize CPU cycle measurement functionality based on DBG | |||
* \return The status of the operation | |||
* \arg LLD_OK Success | |||
* \arg LLD_ERROR Failure | |||
*/ | |||
LLD_Status_en CYCLE_Init (void) { | |||
CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk; // enable trace | |||
//DWT->LAR = 0xC5ACCE55; // <-- added unlock access to DWT (ITM, etc.)registers | |||
DWT->CYCCNT = 0; // clear DWT cycle counter | |||
DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk; // enable DWT cycle counter | |||
return LLD_OK; | |||
} | |||
//! CPU cycle getter | |||
__INLINE clock_t CYCLE_Get (void) { | |||
return (clock_t)DWT->CYCCNT; | |||
} | |||
/* | |||
* =============== Digital I/O =============== | |||
* BTN -- PC13 | |||
* LED -- PA5 (SB42 is in place) [SB29: PB13] | |||
*/ | |||
//! Helper digital input pin getter | |||
static __INLINE uint8_t _DINx (GPIO_TypeDef *port, uint32_t pin) { | |||
return ((port->IDR & pin) != 0) ? 1:0; | |||
} | |||
//! Helper digital output pin setter | |||
static __INLINE uint8_t _DOUTx (GPIO_TypeDef *port, uint32_t pin, uint8_t st) { | |||
if (st) port->BSRR = (uint32_t)pin; | |||
else port->BSRR = (uint32_t)pin << 16; | |||
return st; | |||
} | |||
/*! | |||
* Initialize GPIO port pins for Nucleo Board | |||
* \return The status of the operation | |||
* \arg LLD_OK Success | |||
* \arg LLD_ERROR Failure | |||
*/ | |||
LLD_Status_en Port_Init (void) { | |||
GPIO_InitTypeDef GPIO_InitType; | |||
// Enable Port clock | |||
__HAL_RCC_GPIOA_CLK_ENABLE (); | |||
__HAL_RCC_GPIOC_CLK_ENABLE (); | |||
// BTN port configuration | |||
GPIO_InitType.Mode = GPIO_MODE_INPUT; | |||
GPIO_InitType.Pin = GPIO_PIN_13; | |||
GPIO_InitType.Pull = GPIO_NOPULL; | |||
HAL_GPIO_Init(GPIOC, &GPIO_InitType); | |||
GPIO_InitType.Mode = GPIO_MODE_OUTPUT_PP; | |||
GPIO_InitType.Speed = GPIO_SPEED_LOW; | |||
GPIO_InitType.Pin = GPIO_PIN_5; | |||
HAL_GPIO_Init(GPIOA, &GPIO_InitType); | |||
return LLD_OK; | |||
} | |||
//! Nucleo's user button reader | |||
uint8_t BTN (void) { | |||
return _DINx (GPIOC, GPIO_PIN_13); | |||
} | |||
//! Nucleo's LD2 led setter | |||
void LED (uint8_t on) { | |||
_DOUTx(GPIOA, GPIO_PIN_5, on); | |||
} | |||
/*! Low level driver init functionality | |||
* \return The status of the operation | |||
* \arg LLD_OK Success | |||
* \arg LLD_ERROR Failure | |||
*/ | |||
LLD_Status_en LLD_Init (clock_t sys_freq) { | |||
HAL_Init(); | |||
HAL_SysTick_Init (sys_freq); | |||
CYCLE_Init (); | |||
Port_Init (); | |||
return LLD_OK; | |||
} |
@@ -0,0 +1,137 @@ | |||
/*! | |||
* \file | |||
* NUCLEO_F401RE.h | |||
* \brief | |||
* Nucleo F401RE port file. This file contain the implementation of driver | |||
* calls for F401RE board. | |||
* | |||
* Created on: May 23, 2020 | |||
* Author: Christos Choutouridis AEM: 8997 | |||
* email : <cchoutou@ece.auth.gr> | |||
*/ | |||
#ifndef NUCLEO_F401RE_H_ | |||
#define NUCLEO_F401RE_H_ | |||
#include <stm32f4xx.h> | |||
#include <stm32f4xx_hal.h> | |||
#include <core_cm4.h> | |||
/* | |||
* ========= Data types ======== | |||
*/ | |||
//! Driver status return type | |||
typedef enum { | |||
LLD_OK = 0, //!< Indicate successful operation | |||
LLD_ERROR //!< Indicate Error | |||
}LLD_Status_en; | |||
typedef uint8_t din_t; | |||
//typedef int adc_t; | |||
#define OFF (0) | |||
#define ON (!OFF) | |||
#ifndef FALSE | |||
#define FALSE (0) | |||
#endif | |||
#ifndef TRUE | |||
#define TRUE (!FALSE) | |||
#endif | |||
/* | |||
* =============== System =============== | |||
*/ | |||
#if defined ( __GNUC__ ) && !defined (__CC_ARM) | |||
#include <sys/types.h> | |||
#endif | |||
#include <limits.h> | |||
/* | |||
* Also defined in types.h | |||
*/ | |||
#ifndef _CLOCK_T_ | |||
#define _CLOCK_T_ unsigned long /* clock() */ | |||
typedef _CLOCK_T_ clock_t; /*!< CPU time type */ | |||
#endif | |||
#ifndef _TIME_T_ | |||
#define _TIME_T_ long /* time() */ | |||
typedef _TIME_T_ time_t; /*!< date/time in unix secs past 1-Jan-70 type for 68 years*/ | |||
#endif | |||
/* | |||
* Helper macros | |||
*/ | |||
#define _CLOCK_T_MAX_VALUE_ (ULONG_MAX) //!< Helper macro for maximum signed CPU time calculations | |||
/*! | |||
* Calculate the positive time difference of _t2_ and _t1_, where | |||
* _t1_, _t2_ are clock_t values | |||
* \note | |||
* _t2_ event comes is AFTER _t1_ | |||
* | |||
* ex: | |||
* 0 1 2 3 4 5 6 7 8 9 | |||
* ^ ^ | |||
* | | | |||
* a b | |||
* | |||
* if : t1=a, t2=b then dt = b-a = t2 - t1 | |||
* if : t1=b, t2=a then dt = 9 - (b-a) + 1 = UMAX - (t1-t2) + 1 | |||
* | |||
*/ | |||
#define _CLOCK_DIFF(_t2_, _t1_) ( ((_t2_)>(_t1_)) ? ((_t2_)-(_t1_)) : (_CLOCK_T_MAX_VALUE_ - ((_t1_) - (_t2_)) + 1) ) | |||
/* | |||
* CPU time macros | |||
*/ | |||
#define msec2CPUtime(_ms_) (((_ms_) * get_freq()) / 1000) | |||
#define sec2CPUtime(_s_) ((_s_) * get_freq()) | |||
#define CPUtime2msec(_t_) (((_t_) * 1000) / get_freq()) | |||
#define CPUtime2sec(_t_) ((_t_) / get_freq()) | |||
HAL_StatusTypeDef HAL_SysTick_Init(clock_t sf); | |||
clock_t HAL_SelectSysTickFreq (clock_t sf); | |||
clock_t HAL_GetSysTickFreq (void); | |||
int HAL_SetSysTickFreq (clock_t sf); | |||
/* | |||
* OS like Functionalities | |||
*/ | |||
clock_t get_freq (void); | |||
int set_freq (clock_t sf); | |||
clock_t clock (void); | |||
clock_t setclock (clock_t c); | |||
time_t time (time_t *timer); | |||
int settime (const time_t *t); | |||
/* | |||
* ============== Cycle count ============== | |||
*/ | |||
LLD_Status_en CYCLE_Init (void); | |||
clock_t CYCLE_Get (void); | |||
/* | |||
* =============== Digital I/O =============== | |||
* BTN -- PC13 | |||
* LED -- PA5 (SB42 is in place) [SB29: PB13] | |||
*/ | |||
LLD_Status_en Port_Init (void); | |||
uint8_t BTN (void); | |||
void LED (uint8_t on); | |||
/* | |||
* ============= Board Init ============== | |||
*/ | |||
LLD_Status_en LLD_Init (clock_t sys_freq); | |||
#endif /* NUCLEO_F401RE_H_ */ |
@@ -0,0 +1,63 @@ | |||
/*! | |||
* \file | |||
* assign2_impl.h | |||
* \brief | |||
* Assignment 2 application header | |||
* | |||
* Created on: May 23, 2020 | |||
* Author: Christos Choutouridis AEM: 8997 | |||
* email : <cchoutou@ece.auth.gr> | |||
*/ | |||
#ifndef ASSIGN2_IMPL_H_ | |||
#define ASSIGN2_IMPL_H_ | |||
#include "NUCLEO_F401RE.h" | |||
#include <stdlib.h> | |||
#include <math.h> | |||
/* | |||
* ============= User defines =============== | |||
*/ | |||
#define SYSTICK_FREQ (1000) //!< 1000Hz => 1msec accuracy | |||
#define MODE_LEADING_EDGE (1) //!< Start counting as soon as the led is switched on | |||
#define MODE_TRAILING_EDGE (2) //!< Start counting as soon as the led is switched off (Motor sport style) | |||
//! If there is no Pre-define MODE, select one here | |||
#ifndef MODE | |||
#define MODE MODE_TRAILING_EDGE | |||
#endif | |||
#define MEASUREMENTS (5) //!< The number of measurements for each experiment | |||
//! elect the maximum waiting time before the visual trigger. | |||
#define MAX_WAIT_TIME sec2CPUtime(10) | |||
//! Select if we need cycle counting also. | |||
#define CYCLE_COUNTING (1) | |||
/* | |||
* ============= Data types =============== | |||
*/ | |||
//! Select the application wide accuracy of the floating point type. | |||
typedef float fp_data_t; //!< floating point data alias. | |||
/*! | |||
* Statistical data structure | |||
*/ | |||
typedef struct { | |||
fp_data_t average; //!< The average response time of the experiment | |||
fp_data_t median; //!< The median of the times | |||
fp_data_t std_dev; //!< Standard deviation | |||
} stats_t; | |||
fp_data_t average (const clock_t *t, size_t n); | |||
fp_data_t median (const clock_t *t, size_t n); | |||
fp_data_t std_deviation (const clock_t* t, size_t n); | |||
void leading (clock_t *out, size_t n); | |||
void trailing (clock_t *out, size_t n); | |||
#endif /* ASSIGN2_IMPL_H_ */ |
@@ -0,0 +1,145 @@ | |||
/*! | |||
* \file | |||
* main.c | |||
* \brief | |||
* Main application file | |||
* | |||
* Created on: May 23, 2020 | |||
* Author: Christos Choutouridis AEM: 8997 | |||
* email : <cchoutou@ece.auth.gr> | |||
*/ | |||
#include "assign2_impl.h" | |||
/* | |||
* Global data | |||
*/ | |||
stats_t stats; | |||
/*! | |||
* Compare functionality for qsort | |||
* \param a left hand site | |||
* \param b right hand site | |||
* \return stdlib requirements | |||
* \arg -1 a<b | |||
* \arg 0 a==b | |||
* \arg 1 a>b | |||
*/ | |||
static int cmpfunc (const void * a, const void * b) { | |||
fp_data_t v = *(fp_data_t*)a - *(fp_data_t*)b; | |||
return (v < 0) ? -1 : (v > 0) ? 1 : 0; | |||
} | |||
/*! | |||
* Calculates and return the average of an array of measurements | |||
* \param t Pointer to measurements | |||
* \param n Size of measurements array | |||
* \return The average | |||
*/ | |||
fp_data_t average (const clock_t *t, size_t n) { | |||
fp_data_t ret =0; | |||
for (size_t i=0 ; i<n ; ++i) | |||
ret += t[i]; | |||
return ret / n; | |||
} | |||
/*! | |||
* Calculates and return the median of an array of measurements | |||
* \param t Pointer to measurements | |||
* \param n Size of measurements array | |||
* \return The average | |||
*/ | |||
fp_data_t median (const clock_t *t, size_t n) { | |||
qsort ((void*)t, n, sizeof(t[0]), cmpfunc); | |||
return (n % 2) ? t[n/2] : (t[n/2] + t[n/2 -1]) /2; | |||
} | |||
/*! | |||
* Calculates and return the std. deviation of an array of measurements | |||
* \param t Pointer to measurements | |||
* \param n Size of measurements array | |||
* \return The average | |||
*/ | |||
fp_data_t std_deviation (const clock_t* t, size_t n) { | |||
fp_data_t av = average (t, n); | |||
fp_data_t s =0; | |||
for (size_t i=0 ; i<n ; ++i) { | |||
s += (t[i]-av)*(t[i]-av); | |||
} | |||
return sqrt (s/n); | |||
} | |||
/*! | |||
* Leading edge trigger experiment | |||
* \param out Pointer to array to store the measurements | |||
* \param n Number of measurements | |||
*/ | |||
void leading (clock_t *out, size_t n) { | |||
srand(0); | |||
rand(); | |||
LED (OFF); | |||
for (size_t i =0 ; i<n ; ++i) { | |||
clock_t t1, t2; | |||
HAL_Delay(rand() % (MAX_WAIT_TIME + 1)); | |||
LED(ON); | |||
t1 = clock (); | |||
while (BTN()) | |||
; | |||
t2 = clock (); | |||
LED (OFF); | |||
out[i] = CPUtime2msec(_CLOCK_DIFF(t2, t1)); | |||
} | |||
} | |||
/*! | |||
* Trailing edge trigger experiment | |||
* \param out Pointer to array to store the measurements | |||
* \param n Number of measurements | |||
*/ | |||
void trailing (clock_t *out, size_t n) { | |||
srand(0); | |||
rand(); | |||
LED (ON); | |||
for (size_t i =0 ; i<n ; ++i) { | |||
clock_t t1, t2; | |||
HAL_Delay(rand() % (MAX_WAIT_TIME + 1)); | |||
LED(OFF); | |||
t1 = clock (); | |||
while (BTN()) | |||
; | |||
t2 = clock (); | |||
LED (ON); | |||
out[i] = CPUtime2msec(_CLOCK_DIFF(t2, t1)); | |||
} | |||
} | |||
/* | |||
* Main | |||
*/ | |||
int main(void) { | |||
clock_t times[MEASUREMENTS]; | |||
LLD_Init (SYSTICK_FREQ); // Initialize the board | |||
// Experiment | |||
#if MODE == MODE_LEADING_EDGE | |||
leading (times, MEASUREMENTS); | |||
#elif MODE == MODE_TRAILING_EDGE | |||
trailing (times, MEASUREMENTS); | |||
#endif | |||
// Get statistical data | |||
stats.average = average ((const clock_t*)times, MEASUREMENTS); | |||
stats.median = median ((const clock_t*)times, MEASUREMENTS); | |||
stats.std_dev = std_deviation((const clock_t*)times, MEASUREMENTS); | |||
// Flash 10Hz to indicate the end of experiment | |||
while (1) { | |||
HAL_Delay(msec2CPUtime(50)); | |||
LED (ON); | |||
HAL_Delay(msec2CPUtime(50)); | |||
LED (OFF); | |||
} | |||
} |