// set group of bits
#define _bs(bits,n,m) ((u32)(bits) << ((n) << ((m)-1)))
// clear group of bits
#define _nbs(bits,n,m) ((u32)~(_bs((bits),(n),(m))))
// clear/set 1-bit groups
#define _rm11(r,b,n) (r) = ((r) & _nbs(1,n,1)) | _bs(b,n,1)
#define _rm12(r, b, n1,n2) (r) = ((r) & (_nbs(1,n1,1) & _nbs(1,n2,1))) | (_bs(b,n1,1) | _bs(b,n2,1))
#define _rm13(r, b, n1,n2,n3) (r) = ((r) & (_nbs(1,n1,1) & _nbs(1,n2,1) & _nbs(1,n3,1))) | (_bs(b,n1,1) | _bs(b,n2,1) | _bs(b,n3,1))
#define _rm14(r, b, n1,n2,n3,n4) (r) = ((r) & (_nbs(1,n1,1) & _nbs(1,n2,1) & _nbs(1,n3,1) & _nbs(1,n4,1))) | (_bs(b,n1,1) | _bs(b,n2,1) | _bs(b,n3,1) | _bs(b,n4,1))
#define _rm15(r, b, n1,n2,n3,n4,n5) (r) = ((r) & (_nbs(1,n1,1) & _nbs(1,n2,1) & _nbs(1,n3,1) & _nbs(1,n4,1) & _nbs(1,n5,1))) | (_bs(b,n1,1) | _bs(b,n2,1) | _bs(b,n3,1) | _bs(b,n4,1) | _bs(b,n5,1))
#define _rm16(r, b, n1,n2,n3,n4,n5,n6) (r) = ((r) & (_nbs(1,n1,1) & _nbs(1,n2,1) & _nbs(1,n3,1) & _nbs(1,n4,1) & _nbs(1,n5,1) & _nbs(1,n6,1))) | (_bs(b,n1,1) | _bs(b,n2,1) | _bs(b,n3,1) | _bs(b,n4,1) | _bs(b,n5,1) | _bs(b,n6,1))
// clear/set 2-bit groups
#define _rm21(r,b,n) (r) = ((r) & _nbs(3,n,2)) | _bs(b,n,2)
#define _rm22(r, b, n1,n2) (r) = ((r) & (_nbs(3,n1,2) & _nbs(3,n2,2))) | (_bs(b,n1,2) | _bs(b,n2,2))
#define _rm23(r, b, n1,n2,n3) (r) = ((r) & (_nbs(3,n1,2) & _nbs(3,n2,2) & _nbs(3,n3,2))) | (_bs(b,n1,2) | _bs(b,n2,2) | _bs(b,n3,2))
#define _rm24(r, b, n1,n2,n3,n4) (r) = ((r) & (_nbs(3,n1,2) & _nbs(3,n2,2) & _nbs(3,n3,2) & _nbs(3,n4,2))) | (_bs(b,n1,2) | _bs(b,n2,2) | _bs(b,n3,2) | _bs(b,n4,2))
#define _rm25(r, b, n1,n2,n3,n4,n5) (r) = ((r) & (_nbs(3,n1,2) & _nbs(3,n2,2) & _nbs(3,n3,2) & _nbs(3,n4,2) & _nbs(3,n5,2))) | (_bs(b,n1,2) | _bs(b,n2,2) | _bs(b,n3,2) | _bs(b,n4,2) | _bs(b,n5,2))
#define _rm26(r, b, n1,n2,n3,n4,n5,n6) (r) = ((r) & (_nbs(3,n1,2) & _nbs(3,n2,2) & _nbs(3,n3,2) & _nbs(3,n4,2) & _nbs(3,n5,2) & _nbs(3,n6,2))) | (_bs(b,n1,2) | _bs(b,n2,2) | _bs(b,n3,2) | _bs(b,n4,2) | _bs(b,n5,2) | _bs(b,n6,2))
// configure mode of 1..6 pins
inline void gpio_mode1(GPIO_TypeDef* GPIOx, GPIOMode_TypeDef mode, u32 pin1){ _rm21(GPIOx->MODER, mode, pin1); }
inline void gpio_mode2(GPIO_TypeDef* GPIOx, GPIOMode_TypeDef mode, u32 pin1, u32 pin2){ _rm22(GPIOx->MODER, mode, pin1,pin2); }
inline void gpio_mode3(GPIO_TypeDef* GPIOx, GPIOMode_TypeDef mode, u32 pin1, u32 pin2, u32 pin3){ _rm23(GPIOx->MODER, mode, pin1,pin2,pin3); }
inline void gpio_mode4(GPIO_TypeDef* GPIOx, GPIOMode_TypeDef mode, u32 pin1, u32 pin2, u32 pin3, u32 pin4){ _rm24(GPIOx->MODER, mode, pin1,pin2,pin3,pin4); }
inline void gpio_mode5(GPIO_TypeDef* GPIOx, GPIOMode_TypeDef mode, u32 pin1, u32 pin2, u32 pin3, u32 pin4, u32 pin5){ _rm25(GPIOx->MODER, mode, pin1,pin2,pin3,pin4,pin5); }
inline void gpio_mode6(GPIO_TypeDef* GPIOx, GPIOMode_TypeDef mode, u32 pin1, u32 pin2, u32 pin3, u32 pin4, u32 pin5, u32 pin6){ _rm26(GPIOx->MODER, mode, pin1,pin2,pin3,pin4,pin5,pin6); }
// configure output type of 1..6 pins
inline void gpio_otype1(GPIO_TypeDef* GPIOx, GPIOOType_TypeDef mode, u32 pin1){ _rm11(GPIOx->OTYPER, mode, pin1); }
inline void gpio_otype2(GPIO_TypeDef* GPIOx, GPIOOType_TypeDef mode, u32 pin1, u32 pin2){ _rm12(GPIOx->OTYPER, mode, pin1,pin2); }
inline void gpio_otype3(GPIO_TypeDef* GPIOx, GPIOOType_TypeDef mode, u32 pin1, u32 pin2, u32 pin3){ _rm13(GPIOx->OTYPER, mode, pin1,pin2,pin3); }
inline void gpio_otype4(GPIO_TypeDef* GPIOx, GPIOOType_TypeDef mode, u32 pin1, u32 pin2, u32 pin3, u32 pin4){ _rm14(GPIOx->OTYPER, mode, pin1,pin2,pin3,pin4); }
inline void gpio_otype5(GPIO_TypeDef* GPIOx, GPIOOType_TypeDef mode, u32 pin1, u32 pin2, u32 pin3, u32 pin4, u32 pin5){ _rm15(GPIOx->OTYPER, mode, pin1,pin2,pin3,pin4,pin5); }
inline void gpio_otype6(GPIO_TypeDef* GPIOx, GPIOOType_TypeDef mode, u32 pin1, u32 pin2, u32 pin3, u32 pin4, u32 pin5, u32 pin6){ _rm16(GPIOx->OTYPER, mode, pin1,pin2,pin3,pin4,pin5,pin6); }
// configure speed of 1..6 pins
inline void gpio_ospeed1(GPIO_TypeDef* GPIOx, GPIOSpeed_TypeDef mode, u32 pin1){ _rm21(GPIOx->OSPEEDR, mode, pin1); }
inline void gpio_ospeed2(GPIO_TypeDef* GPIOx, GPIOSpeed_TypeDef mode, u32 pin1, u32 pin2){ _rm22(GPIOx->OSPEEDR, mode, pin1,pin2); }
inline void gpio_ospeed3(GPIO_TypeDef* GPIOx, GPIOSpeed_TypeDef mode, u32 pin1, u32 pin2, u32 pin3){ _rm23(GPIOx->OSPEEDR, mode, pin1,pin2,pin3); }
inline void gpio_ospeed4(GPIO_TypeDef* GPIOx, GPIOSpeed_TypeDef mode, u32 pin1, u32 pin2, u32 pin3, u32 pin4){ _rm24(GPIOx->OSPEEDR, mode, pin1,pin2,pin3,pin4); }
inline void gpio_ospeed5(GPIO_TypeDef* GPIOx, GPIOSpeed_TypeDef mode, u32 pin1, u32 pin2, u32 pin3, u32 pin4, u32 pin5){ _rm25(GPIOx->OSPEEDR, mode, pin1,pin2,pin3,pin4,pin5); }
inline void gpio_ospeed6(GPIO_TypeDef* GPIOx, GPIOSpeed_TypeDef mode, u32 pin1, u32 pin2, u32 pin3, u32 pin4, u32 pin5, u32 pin6){ _rm26(GPIOx->OSPEEDR, mode, pin1,pin2,pin3,pin4,pin5,pin6); }
// configure pull mode of 1..6 pins
inline void gpio_pupd1(GPIO_TypeDef* GPIOx, GPIOPuPd_TypeDef mode, u32 pin1){ _rm21(GPIOx->PUPDR, mode, pin1); }
inline void gpio_pupd2(GPIO_TypeDef* GPIOx, GPIOPuPd_TypeDef mode, u32 pin1, u32 pin2){ _rm22(GPIOx->PUPDR, mode, pin1,pin2); }
inline void gpio_pupd3(GPIO_TypeDef* GPIOx, GPIOPuPd_TypeDef mode, u32 pin1, u32 pin2, u32 pin3){ _rm23(GPIOx->PUPDR, mode, pin1,pin2,pin3); }
inline void gpio_pupd4(GPIO_TypeDef* GPIOx, GPIOPuPd_TypeDef mode, u32 pin1, u32 pin2, u32 pin3, u32 pin4){ _rm24(GPIOx->PUPDR, mode, pin1,pin2,pin3,pin4); }
inline void gpio_pupd5(GPIO_TypeDef* GPIOx, GPIOPuPd_TypeDef mode, u32 pin1, u32 pin2, u32 pin3, u32 pin4, u32 pin5){ _rm25(GPIOx->PUPDR, mode, pin1,pin2,pin3,pin4,pin5); }
inline void gpio_pupd6(GPIO_TypeDef* GPIOx, GPIOPuPd_TypeDef mode, u32 pin1, u32 pin2, u32 pin3, u32 pin4, u32 pin5, u32 pin6){ _rm26(GPIOx->PUPDR, mode, pin1,pin2,pin3,pin4,pin5,pin6); }