Trouble understanding python modules

Discussion and questions about boards that can run MicroPython but don't have a dedicated forum.
Target audience: Everyone interested in running MicroPython on other hardware.
Post Reply
gradoj
Posts: 27
Joined: Mon Aug 11, 2014 5:47 pm

Trouble understanding python modules

Post by gradoj » Fri Jun 12, 2015 10:38 pm

I've written a new module using the LED and UART modules for reference. I am struggling to understand a few points and was hoping someone could explain.

I can't get this function to work unless I remove the self_in variable. I don't understand how this works.

Code: Select all

STATIC mp_uint_t fsmc_obj_write(mp_obj_t self_in,mp_obj_t str)
{
...
}
I need the OBJ_2 function even though I have only on parameter - 'mp_obj_t str'. It seems my module does not know about 'self'.

Code: Select all

STATIC MP_DEFINE_CONST_FUN_OBJ_2(fsmc_obj_write_obj, fsmc_obj_write);

I haven't setup the instance properly in init0 which is probably related:

Code: Select all

#if defined(MICROPY_HW_ENABLE_FSMC)
SRAM_HandleTypeDef hsram = {.Instance = NULL};
NOR_HandleTypeDef exflash = {.Instance = NULL};
#endif
 
void fmsc_init0(void){
	#if defined(MICROPY_HW_ENABLE_FSMC)
	memset(&hsram, 0, sizeof(SRAM_HandleTypeDef));
	memset(&exflash, 0, sizeof(NOR_HandleTypeDef));
	// I don't get this
	//hsram.Instance = ;
	//exflash.Instance = ;
	
	#endif
}
Unlike the LED or UART module where you can have multiple instances of the object the FSMC has only one. Am I over complicating this is there a simpler or better way to do this? Thanks in advance.

User avatar
dhylands
Posts: 3821
Joined: Mon Jan 06, 2014 6:08 pm
Location: Peachland, BC, Canada
Contact:

Re: Trouble understanding python modules

Post by dhylands » Fri Jun 12, 2015 11:28 pm

So you can think of a module as a dictionary of stuff.

That stuff can be functions, constants, classes, or any other python object.

The module is pyb, which is defined in the modpyb.c file, and the module definition is here:
https://github.com/micropython/micropyt ... #L605-L609

If you do:

Code: Select all

>>> import pyb
>>> dir(pyb)
['__name__', 'bootloader', 'hard_reset', 'info', 'unique_id', 'freq', 'repl_info', 'wfi', 'disable_irq', 'enable_irq', 'stop', 'standby', 'main', 'repl_uart', 'usb_mode', 'hid_mouse', 'hid_keyboard', 'USB_VCP', 'USB_HID', 'have_cdc', 'hid', 'millis', 'elapsed_millis', 'micros', 'elapsed_micros', 'delay', 'udelay', 'sync', 'mount', 'Timer', 'rng', 'RTC', 'Pin', 'ExtInt', 'pwm', 'servo', 'Servo', 'Switch', 'SD', 'LED', 'I2C', 'SPI', 'UART', 'CAN', 'ADC', 'ADCAll', 'DAC', 'Accel', 'LCD']
then you'll see that each thing reported by dir comes from the globals table for the module:
https://github.com/micropython/micropyt ... #L513-L601

Now, one of the entries in pyb is UART: https://github.com/micropython/micropyt ... pyb.c#L582
If you query the type of pyb.UART, you'll see that its a type, and if you dir on it you'll see the methods, constants, etc:

Code: Select all

>>> type(pyb.UART)
<class 'type'>
>>> dir(pyb.UART)
['init', 'deinit', 'any', 'read', 'readall', 'readline', 'readinto', 'write', 'writechar', 'readchar', 'sendbreak', 'RTS', 'CTS']
pyb_uart_type is defined in uart.c: https://github.com/micropython/micropyt ... #L814-L823

The .make_new "slot" is what instantiates a new object. So when you do uart = pyb.UART(args) then the function registered against .make_new will be called.

The pyb_uart_make_new function: https://github.com/micropython/micropyt ... #L523-L586 allocates a new pyb_uart_obj_t instance: https://github.com/micropython/micropyt ... art.c#L569 or refers to a previously allocated one (a few lines later).

Only the methods registered against a type will have a self argument. So, for example, in python, you would do:

Code: Select all

>>> my_uart = pyb.UART(6, 115200)
>>> my_uart.writechar('x')
my_uart will be assigned the object that pyb_uart_make_new returned, and uart.writechar will call pyb_uart_writechar https://github.com/micropython/micropyt ... #L656-L671 with self equal to the my_uart instance. Class members will take a self argument and whatever additional arguments are required. In Python, you would do something like this:

Code: Select all

class UART(object):
    def writechar(self, char):
        ...do something...
so writechar takes 2 arguments, self, and char.

Modules can also contain plain old functions. So lets go back to modpyb.c and look at pyb.millis(): https://github.com/micropython/micropyt ... #L342-L354

pyb.millis is just a function, not a class method, so it gets no self argument, and it has no additional arguments, so its declared as a function with no arguments.

So, if what you're to do is to create an FSMC object with methods (so that you could instantiate more than one), then you want to create a type, not a module.

And then the self argument will be required.

Feel free to ask further questions or ask for clarification.

Damien
Site Admin
Posts: 647
Joined: Mon Dec 09, 2013 5:02 pm

Re: Trouble understanding python modules

Post by Damien » Sat Jun 13, 2015 3:38 pm

The RTC class (in rtc.c) is a simple example of something that has only 1 instance.

gradoj
Posts: 27
Joined: Mon Aug 11, 2014 5:47 pm

Re: Trouble understanding python modules

Post by gradoj » Mon Jun 22, 2015 10:50 pm

Thanks for the explanation-I had my terminology all wrong. I used the RTC class as a starting point.

If I run my code through pyboard it seems to work just fine. If I run it at the REPL I get a hardfault. Any ideas what is different between the two methods which would point to my error? I have the REPL echoed to UART1.

This works if I run it with pyboard but I get a 'Hard Fault' on the write line if I use the REPL and run a line at a time:

Code: Select all

data=bytearray((0x00,)*100)
a=pyb.FSMC
a.on()

buf=bytearray(100)
a.write(data,0x64000000)
a.read(0x64000000,100,buf)
print (binascii.hexlify(buf))
I'm assuming I'm doing something incorrectly in the python bindings. Anyone notice anything wrong here:

Code: Select all

STATIC mp_uint_t fsmc_obj_write(const void *buf_in,mp_obj_t addr) {
    	mp_uint_t len = 0;
    	uint32_t a = mp_obj_get_int(addr);
	mp_buffer_info_t bufinfo;
	uint8_t data[1];
	pyb_buf_get_for_send((void *)buf_in, &bufinfo, data);
	len=fsmc_write(a, (const byte *)bufinfo.buf, bufinfo.len);
	return len;
}
Thanks for your help.

Damien
Site Admin
Posts: 647
Joined: Mon Dec 09, 2013 5:02 pm

Re: Trouble understanding python modules

Post by Damien » Tue Jun 23, 2015 8:08 am

Your fsmc write function needs to return a Python object. Change the return type to mp_obj_t and do return mp_obj_new_int(len).

Also the first argument to write should be type mp_obj_t.

gradoj
Posts: 27
Joined: Mon Aug 11, 2014 5:47 pm

Re: Trouble understanding python modules

Post by gradoj » Tue Jun 23, 2015 11:10 pm

Yep, that did it. Everything seems to be working now. Thanks again for your help.

Post Reply