1 /*
2  * Copyright (c) 2022 OpenLuat & AirM2M
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a copy of
5  * this software and associated documentation files (the "Software"), to deal in
6  * the Software without restriction, including without limitation the rights to
7  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
8  * the Software, and to permit persons to whom the Software is furnished to do so,
9  * subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in all
12  * copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
16  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
17  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
18  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20  */
21 
22 #include "user.h"
23 typedef struct
24 {
25     volatile GPIO_TypeDef *RegBase;
26     const int32_t IrqLine;
27     uint16_t ODBitMap;
28 
29 }GPIO_ResourceStruct;
30 
31 typedef struct
32 {
33     CBFuncEx_t AllCB;
34     CBFuncEx_t HWTimerCB;
35     void *pParam;
36 }GPIO_CtrlStruct;
37 
38 static GPIO_CtrlStruct prvGPIO;
39 
40 static GPIO_ResourceStruct prvGPIO_Resource[6] =
41 {
42         {
43                 GPIOA,
44                 EXTI0_IRQn,
45                 0,
46         },
47         {
48                 GPIOB,
49                 EXTI1_IRQn,
50                 0,
51         },
52         {
53                 GPIOC,
54                 EXTI2_IRQn,
55                 0,
56         },
57         {
58                 GPIOD,
59                 EXTI3_IRQn,
60                 0,
61         },
62         {
63                 GPIOE,
64                 EXTI4_IRQn,
65                 0,
66         },
67         {
68                 GPIOF,
69                 EXTI5_IRQn,
70                 0,
71         },
72 };
73 
GPIO_IrqDummyCB(void * pData,void * pParam)74 static int32_t GPIO_IrqDummyCB(void *pData, void *pParam)
75 {
76 //  DBG("%d", pData);
77     return 0;
78 }
GPIO_IrqHandle(int32_t IrqLine,void * pData)79 static void __FUNC_IN_RAM__ GPIO_IrqHandle(int32_t IrqLine, void *pData)
80 {
81     volatile uint32_t Port = (uint32_t)pData;
82     volatile uint32_t Sn, i;
83     if (GPIO->INTP_TYPE_STA[Port].INTP_STA)
84     {
85         Sn = GPIO->INTP_TYPE_STA[Port].INTP_STA;
86         GPIO->INTP_TYPE_STA[Port].INTP_STA = 0xffff;
87         prvGPIO.HWTimerCB((Port << 16) | Sn, prvGPIO.pParam);
88         Port = (Port << 4);
89 
90         for(i = 0; i < 16; i++)
91         {
92             if (Sn & (1 << i))
93             {
94                 prvGPIO.AllCB((void *)(Port+i), 0);
95             }
96         }
97     }
98     ISR_Clear(IrqLine);
99 }
100 
GPIO_GlobalInit(CBFuncEx_t Fun)101 void GPIO_GlobalInit(CBFuncEx_t Fun)
102 {
103     uint32_t i;
104     if (Fun)
105     {
106         prvGPIO.AllCB = Fun;
107     }
108     else
109     {
110         prvGPIO.AllCB = GPIO_IrqDummyCB;
111     }
112     prvGPIO.HWTimerCB = GPIO_IrqDummyCB;
113     for(i = 0; i < 6; i++)
114     {
115         GPIO->INTP_TYPE_STA[i].INTP_TYPE = 0;
116         GPIO->INTP_TYPE_STA[i].INTP_STA = 0xffff;
117 #ifdef __BUILD_OS__
118         ISR_SetPriority(prvGPIO_Resource[i].IrqLine, IRQ_MAX_PRIORITY + 1);
119 #else
120         ISR_SetPriority(prvGPIO_Resource[i].IrqLine, 3);
121 #endif
122         ISR_SetHandler(prvGPIO_Resource[i].IrqLine, GPIO_IrqHandle, (void *)i);
123         ISR_OnOff(prvGPIO_Resource[i].IrqLine, 1);
124     }
125 
126 }
127 
GPIO_Config(uint32_t Pin,uint8_t IsInput,uint8_t InitValue)128 void __FUNC_IN_RAM__ GPIO_Config(uint32_t Pin, uint8_t IsInput, uint8_t InitValue)
129 {
130     uint8_t Port = (Pin >> 4);
131     uint8_t orgPin = Pin;
132     Pin = 1 << (Pin & 0x0000000f);
133     GPIO_Iomux(orgPin, 1);
134     if (IsInput)
135     {
136         prvGPIO_Resource[Port].RegBase->OEN |= Pin;
137     }
138     else
139     {
140         prvGPIO_Resource[Port].RegBase->BSRR |= InitValue?Pin:(Pin << 16);
141         prvGPIO_Resource[Port].RegBase->OEN &= ~Pin;
142     }
143     prvGPIO_Resource[Port].ODBitMap &= ~Pin;
144 }
145 
GPIO_ODConfig(uint32_t Pin,uint8_t InitValue)146 void __FUNC_IN_RAM__ GPIO_ODConfig(uint32_t Pin, uint8_t InitValue)
147 {
148     uint8_t Port = (Pin >> 4);
149     uint8_t orgPin = Pin;
150     Pin = 1 << (Pin & 0x0000000f);
151     GPIO_Iomux(orgPin, 1);
152     prvGPIO_Resource[Port].RegBase->OEN |= Pin;
153     if (InitValue)
154     {
155         prvGPIO_Resource[Port].RegBase->PUE |= Pin;
156     }
157     else
158     {
159         prvGPIO_Resource[Port].RegBase->PUE &= ~Pin;
160     }
161     prvGPIO_Resource[Port].ODBitMap |= Pin;
162 }
163 
GPIO_PullConfig(uint32_t Pin,uint8_t IsPull,uint8_t IsUp)164 void __FUNC_IN_RAM__ GPIO_PullConfig(uint32_t Pin, uint8_t IsPull, uint8_t IsUp)
165 {
166     uint8_t Port = (Pin >> 4);
167     Pin = 1 << (Pin & 0x0000000f);
168     if (IsPull && IsUp)
169     {
170         prvGPIO_Resource[Port].RegBase->PUE |= Pin;
171     }
172     else
173     {
174         prvGPIO_Resource[Port].RegBase->PUE &= ~Pin;
175     }
176 }
177 
GPIO_ExtiConfig(uint32_t Pin,uint8_t IsLevel,uint8_t IsRiseHigh,uint8_t IsFallLow)178 void GPIO_ExtiConfig(uint32_t Pin, uint8_t IsLevel, uint8_t IsRiseHigh, uint8_t IsFallLow)
179 {
180     uint8_t Port = (Pin >> 4);
181     uint32_t Type = 0;
182     uint32_t Mask = ~(0x03 << ((Pin & 0x0000000f) * 2));
183     if (!IsLevel)
184     {
185         if (IsRiseHigh && IsFallLow)
186         {
187             Type = 0x03 << ((Pin & 0x0000000f) * 2);
188         }
189         else if (IsFallLow)
190         {
191             Type = 0x02 << ((Pin & 0x0000000f) * 2);
192         }
193         else if (IsRiseHigh)
194         {
195             Type = 0x01 << ((Pin & 0x0000000f) * 2);
196         }
197     }
198     GPIO->INTP_TYPE_STA[Port].INTP_TYPE = (GPIO->INTP_TYPE_STA[Port].INTP_TYPE & Mask) | Type;
199 }
200 
GPIO_ExtiSetHWTimerCB(CBFuncEx_t CB,void * pParam)201 void GPIO_ExtiSetHWTimerCB(CBFuncEx_t CB, void *pParam)
202 {
203     if (CB)
204     {
205         prvGPIO.HWTimerCB = CB;
206     }
207     else
208     {
209         prvGPIO.HWTimerCB = GPIO_IrqDummyCB;
210     }
211     prvGPIO.pParam = pParam;
212 }
213 
GPIO_Iomux(uint32_t Pin,uint32_t Function)214 void __FUNC_IN_RAM__ GPIO_Iomux(uint32_t Pin, uint32_t Function)
215 {
216     uint8_t Port = (Pin >> 4);
217     uint32_t Mask = ~(0x03 << ((Pin & 0x0000000f) * 2));
218     Function = Function << ((Pin & 0x0000000f) * 2);
219     GPIO->ALT[Port] = (GPIO->ALT[Port] & Mask) | Function;
220 }
221 
GPIO_Output(uint32_t Pin,uint8_t Level)222 void __FUNC_IN_RAM__ GPIO_Output(uint32_t Pin, uint8_t Level)
223 {
224     uint8_t Port = (Pin >> 4);
225     Pin = 1 << (Pin & 0x0000000f);
226     if (prvGPIO_Resource[Port].ODBitMap & Pin)
227     {
228         if (Level)
229         {
230             prvGPIO_Resource[Port].RegBase->PUE |= Pin;
231         }
232         else
233         {
234             prvGPIO_Resource[Port].RegBase->PUE &= ~Pin;
235         }
236     }
237     else
238     {
239         prvGPIO_Resource[Port].RegBase->BSRR |= Level?Pin:(Pin << 16);
240     }
241 
242 //  DBG("%d, %x, %x, %x",Port, Pin, prvGPIO_Resource[Port].RegBase, prvGPIO_Resource[Port].RegBase->IODR);
243 }
244 
GPIO_Input(uint32_t Pin)245 uint8_t __FUNC_IN_RAM__ GPIO_Input(uint32_t Pin)
246 {
247     uint8_t Port = (Pin >> 4);
248     Pin = 1 << (Pin & 0x0000000f);
249     return (prvGPIO_Resource[Port].RegBase->IODR & (Pin << 16))?1:0;
250 }
251 
GPIO_OutputMulti(uint32_t Port,uint32_t Pins,uint32_t Level)252 void __FUNC_IN_RAM__ GPIO_OutputMulti(uint32_t Port, uint32_t Pins, uint32_t Level)
253 {
254     prvGPIO_Resource[Port].RegBase->BSRR |= Level?Pins:(Pins << 16);
255 }
256 
GPIO_InputMulti(uint32_t Port)257 uint32_t __FUNC_IN_RAM__ GPIO_InputMulti(uint32_t Port)
258 {
259     return (prvGPIO_Resource[Port].RegBase->IODR >> 16);
260 }
261